--- /dev/null
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233208.133827759@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:33 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Russell King <rmk+kernel@arm.linux.org.uk>,
+ Takashi Iwai <tiwai@suse.de>
+Subject: [01/20] ALSA: AACI: fix AC97 multiple-open bug
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=alsa-aaci-fix-ac97-multiple-open-bug.patch
+Content-Length: 661
+Lines: 26
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+
+commit 4acd57c3de62374fe5bb52e5cd24538190f4eab2 upstream.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/arm/aaci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/arm/aaci.c
++++ b/sound/arm/aaci.c
+@@ -504,6 +504,10 @@ static int aaci_pcm_hw_params(struct snd
+ int err;
+
+ aaci_pcm_hw_free(substream);
++ if (aacirun->pcm_open) {
++ snd_ac97_pcm_close(aacirun->pcm);
++ aacirun->pcm_open = 0;
++ }
+
+ err = devdma_hw_alloc(NULL, substream,
+ params_buffer_bytes(params));
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233208.269420973@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:34 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Russell King <rmk+kernel@arm.linux.org.uk>,
+ Takashi Iwai <tiwai@suse.de>
+Subject: [02/20] ALSA: AACI: fix recording bug
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=alsa-aaci-fix-recording-bug.patch
+Content-Length: 794
+Lines: 28
+
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+
+commit 8ee763b9c82c6ca0a59a7271ce4fa29d7baf5c09 upstream.
+
+pcm->r[1].slots is the double rate slot information, not the
+capture information. For capture, 'pcm' will already be the
+capture ac97 pcm structure.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/arm/aaci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/arm/aaci.c
++++ b/sound/arm/aaci.c
+@@ -521,7 +521,7 @@ static int aaci_pcm_hw_params(struct snd
+ else
+ err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params),
+ params_channels(params),
+- aacirun->pcm->r[1].slots);
++ aacirun->pcm->r[0].slots);
+
+ if (err)
+ goto out;
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233208.427626071@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:35 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Julian Anastasov <ja@ssi.bg>,
+ Takashi Iwai <tiwai@suse.de>
+Subject: [03/20] ALSA: usb-audio: fix combine_word problem
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=alsa-usb-audio-fix-combine_word-problem.patch
+Content-Length: 1318
+Lines: 39
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Julian Anastasov <ja@ssi.bg>
+
+commit f495088210c8b9e20791d995a8210170c68d2deb upstream.
+
+Fix combine_word problem where first octet is not
+read properly. The only affected place seems to be the
+INPUT_TERMINAL type. Before now, sound controls can be created
+with the output terminal's name which is a fallback mechanism
+used only for unknown input terminal types. For example,
+Line can wrongly appear as Speaker. After the change it
+should appear as Line.
+
+ The side effect of this change can be that users
+can expect the wrong control name in their scripts or
+programs while now we return the correct one.
+
+ Probably, these defines should use get_unaligned_le16 and
+friends.
+
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/usb/usbaudio.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/usb/usbaudio.h
++++ b/sound/usb/usbaudio.h
+@@ -209,7 +209,7 @@ struct snd_usb_midi_endpoint_info {
+ /*
+ */
+
+-#define combine_word(s) ((*s) | ((unsigned int)(s)[1] << 8))
++#define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8))
+ #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16))
+ #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24))
+
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233208.580098254@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:36 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Dave Jones <davej@redhat.com>,
+ James Bottomley <James.Bottomley@suse.de>
+Subject: [04/20] [SCSI] gdth: Prevent negative offsets in ioctl CVE-2009-3080
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=gdth-prevent-negative-offsets-in-ioctl-cve-2009-3080.patch
+Content-Length: 769
+Lines: 27
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Dave Jones <davej@redhat.com>
+
+commit 690e744869f3262855b83b4fb59199cf142765b0 upstream.
+
+A negative offset could be used to index before the event buffer and
+lead to a security breach.
+
+Signed-off-by: Dave Jones <davej@redhat.com>
+Signed-off-by: James Bottomley <James.Bottomley@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/scsi/gdth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/gdth.c
++++ b/drivers/scsi/gdth.c
+@@ -2912,7 +2912,7 @@ static int gdth_read_event(gdth_ha_str *
+ eindex = handle;
+ estr->event_source = 0;
+
+- if (eindex >= MAX_EVENTS) {
++ if (eindex < 0 || eindex >= MAX_EVENTS) {
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+ return eindex;
+ }
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233208.744542128@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:37 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ David Woodhouse <David.Woodhouse@intel.com>
+Subject: [05/20] jffs2: Fix memory corruption in jffs2_read_inode_range()
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=jffs2-fix-memory-corruption-in-jffs2_read_inode_range.patch
+Content-Length: 3423
+Lines: 80
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: David Woodhouse <dwmw2@infradead.org>
+
+commit 199bc9ff5ca5e4b3bcaff8927b2983c65f34c263 upstream.
+
+In 2.6.23 kernel, commit a32ea1e1f925399e0d81ca3f7394a44a6dafa12c
+("Fix read/truncate race") fixed a race in the generic code, and as a
+side effect, now do_generic_file_read() can ask us to readpage() past
+the i_size. This seems to be correctly handled by the block routines
+(e.g. block_read_full_page() fills the page with zeroes in case if
+somebody is trying to read past the last inode's block).
+
+JFFS2 doesn't handle this; it assumes that it won't be asked to read
+pages which don't exist -- and thus that there will be at least _one_
+valid 'frag' on the page it's being asked to read. It will fill any
+holes with the following memset:
+
+ memset(buf, 0, min(end, frag->ofs + frag->size) - offset);
+
+When the 'closest smaller match' returned by jffs2_lookup_node_frag() is
+actually on a previous page and ends before 'offset', that results in:
+
+ memset(buf, 0, <huge unsigned negative>);
+
+Hopefully, in most cases the corruption is fatal, and quickly causing
+random oopses, like this:
+
+ root@10.0.0.4:~/ltp-fs-20090531# ./testcases/kernel/fs/ftest/ftest01
+ Unable to handle kernel paging request for data at address 0x00000008
+ Faulting instruction address: 0xc01cd980
+ Oops: Kernel access of bad area, sig: 11 [#1]
+ [...]
+ NIP [c01cd980] rb_insert_color+0x38/0x184
+ LR [c0043978] enqueue_hrtimer+0x88/0xc4
+ Call Trace:
+ [c6c63b60] [c004f9a8] tick_sched_timer+0xa0/0xe4 (unreliable)
+ [c6c63b80] [c0043978] enqueue_hrtimer+0x88/0xc4
+ [c6c63b90] [c0043a48] __run_hrtimer+0x94/0xbc
+ [c6c63bb0] [c0044628] hrtimer_interrupt+0x140/0x2b8
+ [c6c63c10] [c000f8e8] timer_interrupt+0x13c/0x254
+ [c6c63c30] [c001352c] ret_from_except+0x0/0x14
+ --- Exception: 901 at memset+0x38/0x5c
+ LR = jffs2_read_inode_range+0x144/0x17c
+ [c6c63cf0] [00000000] (null) (unreliable)
+
+This patch fixes the issue, plus fixes all LTP tests on NAND/UBI with
+JFFS2 filesystem that were failing since 2.6.23 (seems like the bug
+above also broke the truncation).
+
+Reported-By: Anton Vorontsov <avorontsov@ru.mvista.com>
+Tested-By: Anton Vorontsov <avorontsov@ru.mvista.com>
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/jffs2/read.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/fs/jffs2/read.c
++++ b/fs/jffs2/read.c
+@@ -164,12 +164,15 @@ int jffs2_read_inode_range(struct jffs2_
+
+ /* XXX FIXME: Where a single physical node actually shows up in two
+ frags, we read it twice. Don't do that. */
+- /* Now we're pointing at the first frag which overlaps our page */
++ /* Now we're pointing at the first frag which overlaps our page
++ * (or perhaps is before it, if we've been asked to read off the
++ * end of the file). */
+ while(offset < end) {
+ D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
+- if (unlikely(!frag || frag->ofs > offset)) {
++ if (unlikely(!frag || frag->ofs > offset ||
++ frag->ofs + frag->size <= offset)) {
+ uint32_t holesize = end - offset;
+- if (frag) {
++ if (frag && frag->ofs > offset) {
+ D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
+ holesize = min(holesize, frag->ofs - offset);
+ }
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233208.909016800@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:38 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Martin Samek <martin@marsark.sytes.net>,
+ Devin Heitmueller <dheitmueller@kernellabs.com>,
+ Mauro Carvalho Chehab <mchehab@redhat.com>
+Subject: [06/20] V4L/DVB (13079): dib0700: fixed xc2028 firmware loading kernel oops
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=v4l-dvb-13079-dib0700-fixed-xc2028-firmware-loading-kernel-oops.patch
+Content-Length: 1410
+Lines: 36
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Martin Samek <martin@marsark.sytes.net>
+
+commit 7646b9de26c54cf4bc9c446d7ada9f91ece31e0a upstream.
+
+Fixing kernel oops when driver attemps to load xc2028 firmware.
+
+Note by djh: the patch contribute by Martin is a port of a fix I made during
+the PCTV 340e development. It's a temporary workaround that fixes a regression
+(an OOPS condition) and the real fix should be in the code that manages the
+i2c master on the dib7000p. But this fix does address the immmediate
+regression and should be merged upstream until we do a cleaner fix.
+
+Signed-off-by: Martin Samek <martin@marsark.sytes.net>
+Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/frontends/dib7000p.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -1343,6 +1343,11 @@ struct dvb_frontend * dib7000p_attach(st
+ if (dib7000p_identify(st) != 0)
+ goto error;
+
++ /* FIXME: make sure the dev.parent field is initialized, or else
++ 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);
+
+ dib7000p_demod_reset(st);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233209.140733272@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:39 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Henk Vergonet <Henk.Vergonet@gmail.com>,
+ Michael Krufky <mkrufky@kernellabs.com>,
+ Mauro Carvalho Chehab <mchehab@redhat.com>
+Subject: [07/20] V4L/DVB (13107): tda18271: fix overflow in FM radio frequency calculation
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=v4l-dvb-13107-tda18271-fix-overflow-in-fm-radio-frequency-calculation.patch
+Content-Length: 1300
+Lines: 38
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Michael Krufky <mkrufky@kernellabs.com>
+
+commit 4d8317876d5f53ef792e90f89d8f162d7bca5c81 upstream.
+
+Multiplication by 62500 causes an overflow in the 32 bit freq variable,
+which is later divided by 1000 when using FM radio.
+
+This patch prevents the overflow by scaling the frequency value correctly
+upfront. Thanks to Henk Vergonet for spotting the problem and providing
+a preliminary patch, which this changeset was based upon.
+
+Cc: Henk Vergonet <Henk.Vergonet@gmail.com>
+Signed-off-by: Michael Krufky <mkrufky@kernellabs.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/common/tuners/tda18271-fe.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/common/tuners/tda18271-fe.c
++++ b/drivers/media/common/tuners/tda18271-fe.c
+@@ -927,12 +927,12 @@ static int tda18271_set_analog_params(st
+ struct tda18271_std_map_item *map;
+ char *mode;
+ int ret;
+- u32 freq = params->frequency * 62500;
++ u32 freq = params->frequency * 125 *
++ ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2;
+
+ priv->mode = TDA18271_ANALOG;
+
+ if (params->mode == V4L2_TUNER_RADIO) {
+- freq = freq / 1000;
+ map = &std_map->fm_radio;
+ mode = "fm";
+ } else if (params->std & V4L2_STD_MN) {
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233209.309431448@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:40 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Seth Barry <seth@cyberseth.com>,
+ Michael Krufky <mkrufky@kernellabs.com>,
+ Mauro Carvalho Chehab <mchehab@redhat.com>
+Subject: [08/20] V4L/DVB (13109): tda18271: fix signedness issue in tda18271_rf_tracking_filters_init
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=v4l-dvb-13109-tda18271-fix-signedness-issue-in-tda18271_rf_tracking_filters_init.patch
+Content-Length: 2897
+Lines: 61
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Seth Barry <seth@cyberseth.com>
+
+commit a57c1dcb93e43357ed3f666e5a2b5d5071dd3930 upstream.
+
+While having tda18271 module set with debug=17 (cal & info prints) and
+cal=0 (delay calibration process until first use) - I discovered that
+during the calibration process, if the frequency test for 69750000
+returned a bcal of 0 (see tda18721-fe.c in tda18271_powerscan func) that
+the tuner wouldn't be able to pickup any of the frequencies in the range
+(all the other frequencies bands returned bcal=1). I spent some time
+going over the code and the NXP's tda18271 spec (ver.4 of it i think) and
+adding a lot of debug prints and walking/stepping through the calibration
+process. I found that when the powerscan fails to find a frequency, the
+rf calibration is not run and the default value is supposed to be used in
+its place (pulled from the RF_CAL_map table) - but something was getting
+goofed up there.
+
+Now, my c coding skills are very rusty, but i think root of the problem is
+a signedness issue with the math operation for calculating the rf_a1 and
+rf_a2 values in tda18271_rf_tracking_filters_init func, which results in
+values like 20648 for rf_a1 (when it should probably have a value like 0,
+or so slightly negative that it should be zero - this bad value for rf_a1
+would in turn makes the approx calc within
+tda18271c2_rf_tracking_filters_correction go out of whack). The simplest
+solution i found was to explicitly convert the signedness of the
+denominator to avoid the implicit conversion. The values placed into the
+u32 rf_freq array should never exceed about 900mhz, so i think the s32 max
+value shouldn't be an issue in this case.
+
+I've tested it out a little, and even when i get a bcal=0 with the
+modified code, the default calibration value gets used, rf_a1 is zero, and
+the tuner seems to lock on the stream and mythtv seems to play it fine.
+
+Signed-off-by: Seth Barry <seth@cyberseth.com>
+Signed-off-by: Michael Krufky <mkrufky@kernellabs.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/common/tuners/tda18271-fe.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/common/tuners/tda18271-fe.c
++++ b/drivers/media/common/tuners/tda18271-fe.c
+@@ -595,13 +595,13 @@ static int tda18271_rf_tracking_filters_
+ case RF2:
+ map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
+ prog_cal[RF1] + prog_tab[RF1]) /
+- ((rf_freq[RF2] - rf_freq[RF1]) / 1000);
++ (s32)((rf_freq[RF2] - rf_freq[RF1]) / 1000);
+ map[i].rf2 = rf_freq[RF2] / 1000;
+ break;
+ case RF3:
+ map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
+ prog_cal[RF2] + prog_tab[RF2]) /
+- ((rf_freq[RF3] - rf_freq[RF2]) / 1000);
++ (s32)((rf_freq[RF3] - rf_freq[RF2]) / 1000);
+ map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
+ map[i].rf3 = rf_freq[RF3] / 1000;
+ break;
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233209.440225308@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:41 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Devin Heitmueller <dheitmueller@kernellabs.com>,
+ Mauro Carvalho Chehab <mchehab@redhat.com>
+Subject: [09/20] V4L/DVB (13190): em28xx: fix panic that can occur when starting audio streaming
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=v4l-dvb-13190-em28xx-fix-panic-that-can-occur-when-starting-audio-streaming.patch
+Content-Length: 1170
+Lines: 34
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Devin Heitmueller <dheitmueller@kernellabs.com>
+
+commit 96fbf771d86a90ff006bc62ca4d4de6474b3de31 upstream.
+
+Because the counters were not reset when starting up streaming, they would
+be reused from the previous run. This can result in cases such that when the
+second instance of streaming starts up, the "cnt" variable in
+em28xx_audio_isocirq() can end up being negative, resulting in attempting to
+write to memory before the start of runtime->dma_area (as well as having a
+negative number of bytes to copy).
+
+Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/em28xx/em28xx-audio.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/media/video/em28xx/em28xx-audio.c
++++ b/drivers/media/video/em28xx/em28xx-audio.c
+@@ -365,6 +365,11 @@ static int snd_em28xx_hw_capture_free(st
+
+ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
+ {
++ struct em28xx *dev = snd_pcm_substream_chip(substream);
++
++ dev->adev.hwptr_done_capture = 0;
++ dev->adev.capture_transfer_done = 0;
++
+ return 0;
+ }
+
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233209.565626658@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:42 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Mike Isely <isely@pobox.com>,
+ Mauro Carvalho Chehab <mchehab@redhat.com>
+Subject: [10/20] V4L/DVB (13230): s2255drv: Dont conditionalize video buffer completion on waiting processes
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=v4l-dvb-13230-s2255drv-don-t-conditionalize-video-buffer-completion-on-waiting-processes.patch
+Content-Length: 1820
+Lines: 44
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Mike Isely <isely@pobox.com>
+
+commit 1f95725755ab67f3198df3b5bf7517f926f310ca upstream.
+
+The s2255 driver had logic which aborted processing of a video frame
+if there was no process waiting on the video buffer in question. That
+simply doesn't work when the application is doing things in an
+asynchronous manner. If the application went to the trouble to queue
+the buffer in the first place, then the driver should always attempt
+to complete it - even if the application at that moment has its
+attention turned elsewhere. Applications which always blocked waiting
+for I/O on the capture device would not have been affected by this.
+Applications which *mostly* blocked waiting for I/O on the capture
+device probably only would have been somewhat affected (frame lossage,
+at a rate which goes up as the application blocks less). Applications
+which never blocked on the capture device (e.g. polling only) however
+would never have been able to receive any video frames, since in that
+case this "is anyone waiting on this?" check on the buffer never would
+have evalutated true. This patch just deletes that harmful check
+against the buffer's wait queue.
+
+Signed-off-by: Mike Isely <isely@pobox.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/s2255drv.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/media/video/s2255drv.c
++++ b/drivers/media/video/s2255drv.c
+@@ -578,11 +578,6 @@ static int s2255_got_frame(struct s2255_
+ buf = list_entry(dma_q->active.next,
+ struct s2255_buffer, vb.queue);
+
+- if (!waitqueue_active(&buf->vb.done)) {
+- /* no one active */
+- rc = -1;
+- goto unlock;
+- }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:09 2009
+Message-Id: <20091206233209.736223758@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:43 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Harald Welte <HaraldWelte@viatech.com>,
+ Dave Jones <davej@redhat.com>
+Subject: [11/20] [CPUFREQ] Enable ACPI PDC handshake for VIA/Centaur CPUs
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=enable-acpi-pdc-handshake-for-via-centaur-cpus.patch
+Content-Length: 1447
+Lines: 40
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Harald Welte <HaraldWelte@viatech.com>
+
+commit d77b81974521c82fa6fda38dfff1b491dcc62a32 upstream.
+
+In commit 0de51088e6a82bc8413d3ca9e28bbca2788b5b53, we introduced the
+use of acpi-cpufreq on VIA/Centaur CPU's by removing a vendor check for
+VENDOR_INTEL. However, as it turns out, at least the Nano CPU's also
+need the PDC (processor driver capabilities) handshake in order to
+activate the methods required for acpi-cpufreq.
+
+Since arch_acpi_processor_init_pdc() contains another vendor check for
+Intel, the PDC is not initialized on VIA CPU's. The resulting behavior
+of a current mainline kernel on such systems is: acpi-cpufreq
+loads and it indicates CPU frequency changes. However, the CPU stays at
+a single frequency
+
+This trivial patch ensures that init_intel_pdc() is called on Intel and
+VIA/Centaur CPU's alike.
+
+Signed-off-by: Harald Welte <HaraldWelte@viatech.com>
+Signed-off-by: Dave Jones <davej@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/acpi/processor.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/acpi/processor.c
++++ b/arch/x86/kernel/acpi/processor.c
+@@ -78,7 +78,8 @@ void arch_acpi_processor_init_pdc(struct
+ struct cpuinfo_x86 *c = &cpu_data(pr->id);
+
+ pr->pdc = NULL;
+- if (c->x86_vendor == X86_VENDOR_INTEL)
++ if (c->x86_vendor == X86_VENDOR_INTEL ||
++ c->x86_vendor == X86_VENDOR_CENTAUR)
+ init_intel_pdc(pr, c);
+
+ return;
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233209.900445809@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:44 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Csaba Henk <csaba@gluster.com>,
+ Miklos Szeredi <mszeredi@suse.cz>,
+ Harshavardhana <harsha@gluster.com>
+Subject: [12/20] fuse: reject O_DIRECT flag also in fuse_create
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=fuse-reject-o_direct-flag-also-in-fuse_create.patch
+Content-Length: 1088
+Lines: 39
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Csaba Henk <csaba@gluster.com>
+
+commit 1b7323965a8c6eee9dc4e345a7ae4bff1dc93149 upstream.
+
+The comment in fuse_open about O_DIRECT:
+
+ "VFS checks this, but only _after_ ->open()"
+
+also holds for fuse_create, however, the same kind of check was missing there.
+
+As an impact of this bug, open(newfile, O_RDWR|O_CREAT|O_DIRECT) fails, but a
+stub newfile will remain if the fuse server handled the implied FUSE_CREATE
+request appropriately.
+
+Other impact: in the above situation ima_file_free() will complain to open/free
+imbalance if CONFIG_IMA is set.
+
+Signed-off-by: Csaba Henk <csaba@gluster.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Cc: Harshavardhana <harsha@gluster.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/fuse/dir.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -398,6 +398,9 @@ static int fuse_create_open(struct inode
+ if (fc->no_create)
+ return -ENOSYS;
+
++ if (flags & O_DIRECT)
++ return -EINVAL;
++
+ forget_req = fuse_get_req(fc);
+ if (IS_ERR(forget_req))
+ return PTR_ERR(forget_req);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.067773370@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:45 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ "Anand V. Avati" <avati@gluster.com>,
+ Miklos Szeredi <mszeredi@suse.cz>
+Subject: [13/20] fuse: prevent fuse_put_request on invalid pointer
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=fuse-prevent-fuse_put_request-on-invalid-pointer.patch
+Content-Length: 808
+Lines: 29
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Anand V. Avati <avati@gluster.com>
+
+commit f60311d5f7670d9539b424e4ed8b5c0872fc9e83 upstream.
+
+fuse_direct_io() has a loop where requests are allocated in each
+iteration. if allocation fails, the loop is broken out and follows
+into an unconditional fuse_put_request() on that invalid pointer.
+
+Signed-off-by: Anand V. Avati <avati@gluster.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/fuse/file.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -1005,7 +1005,8 @@ static ssize_t fuse_direct_io(struct fil
+ break;
+ }
+ }
+- fuse_put_request(fc, req);
++ if (!IS_ERR(req))
++ fuse_put_request(fc, req);
+ if (res > 0) {
+ if (write)
+ fuse_write_update_size(inode, pos);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.240780761@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:46 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Roel Kluin <roel.kluin@gmail.com>,
+ Karsten Keil <isdn@linux-pingi.de>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [14/20] isdn: hfc_usb: Fix read buffer overflow
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=isdn-hfc_usb-fix-read-buffer-overflow.patch
+Content-Length: 939
+Lines: 30
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Roel Kluin <roel.kluin@gmail.com>
+
+commit 286e633ef0ff5bb63c07b4516665da8004966fec upstream.
+
+Check whether index is within bounds before testing the element.
+
+Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
+Cc: Karsten Keil <isdn@linux-pingi.de>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/isdn/hisax/hfc_usb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/isdn/hisax/hfc_usb.c
++++ b/drivers/isdn/hisax/hfc_usb.c
+@@ -818,8 +818,8 @@ collect_rx_frame(usb_fifo * fifo, __u8 *
+ }
+ /* we have a complete hdlc packet */
+ if (finish) {
+- if ((!fifo->skbuff->data[fifo->skbuff->len - 1])
+- && (fifo->skbuff->len > 3)) {
++ if (fifo->skbuff->len > 3 &&
++ !fifo->skbuff->data[fifo->skbuff->len - 1]) {
+
+ if (fifon == HFCUSB_D_RX) {
+ DBG(HFCUSB_DBG_DCHANNEL,
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.382595495@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:47 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Roel Kluin <roel.kluin@gmail.com>,
+ Henrique de Moraes Holschuh <hmh@hmh.eng.br>,
+ Len Brown <len.brown@intel.com>
+Subject: [15/20] thinkpad-acpi: fix sign of ERESTARTSYS return
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=thinkpad-acpi-fix-sign-of-erestartsys-return.patch
+Content-Length: 874
+Lines: 28
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Roel Kluin <roel.kluin@gmail.com>
+
+commit 80a8d1228e90349b4514e8c925c061fa5cbcea75 upstream.
+
+The returned error should be negative
+
+Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
+Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/misc/thinkpad_acpi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -5042,7 +5042,7 @@ static int brightness_write(char *buf)
+ * Doing it this way makes the syscall restartable in case of EINTR
+ */
+ rc = brightness_set(level);
+- return (rc == -EINTR)? ERESTARTSYS : rc;
++ return (rc == -EINTR)? -ERESTARTSYS : rc;
+ }
+
+ static struct ibm_struct brightness_driver_data = {
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.538424805@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:48 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Libin Yang <libin.yang@amd.com>,
+ David Brownell <dbrownell@users.sourceforge.net>,
+ Alan Stern <stern@rowland.harvard.edu>
+Subject: [16/20] USB: ohci: quirk AMD prefetch for USB 1.1 ISO transfer
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=usb-ohci-quirk-amd-prefetch-for-usb-1.1-iso-transfer.patch
+Content-Length: 4442
+Lines: 145
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Libin Yang <libin.yang@amd.com>
+
+commit a1f17a872bc7b1cb7efdd5486a2963e88a536e61 upstream.
+
+The following patch in the driver is required to avoid USB 1.1 device
+failures that may occur due to requests from USB OHCI controllers may
+be overwritten if the latency for any pending request by the USB
+controller is very long (in the range of milliseconds).
+
+Signed-off-by: Libin Yang <libin.yang@amd.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Cc: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-hcd.c | 5 +++++
+ drivers/usb/host/ohci-pci.c | 20 ++++++++++++++++++++
+ drivers/usb/host/ohci-q.c | 18 ++++++++++++------
+ drivers/usb/host/ohci.h | 9 +++++++++
+ 4 files changed, 46 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -89,6 +89,7 @@ static int ohci_restart (struct ohci_hcd
+ #ifdef CONFIG_PCI
+ static void quirk_amd_pll(int state);
+ static void amd_iso_dev_put(void);
++static void sb800_prefetch(struct ohci_hcd *ohci, int on);
+ #else
+ static inline void quirk_amd_pll(int state)
+ {
+@@ -98,6 +99,10 @@ static inline void amd_iso_dev_put(void)
+ {
+ return;
+ }
++static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
++{
++ return;
++}
+ #endif
+
+
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -177,6 +177,13 @@ static int ohci_quirk_amd700(struct usb_
+ return 0;
+
+ pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
++
++ /* SB800 needs pre-fetch fix */
++ if ((rev >= 0x40) && (rev <= 0x4f)) {
++ ohci->flags |= OHCI_QUIRK_AMD_PREFETCH;
++ ohci_dbg(ohci, "enabled AMD prefetch quirk\n");
++ }
++
+ if ((rev > 0x3b) || (rev < 0x30)) {
+ pci_dev_put(amd_smbus_dev);
+ amd_smbus_dev = NULL;
+@@ -262,6 +269,19 @@ static void amd_iso_dev_put(void)
+
+ }
+
++static void sb800_prefetch(struct ohci_hcd *ohci, int on)
++{
++ struct pci_dev *pdev;
++ u16 misc;
++
++ pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller);
++ pci_read_config_word(pdev, 0x50, &misc);
++ if (on == 0)
++ pci_write_config_word(pdev, 0x50, misc & 0xfcff);
++ else
++ pci_write_config_word(pdev, 0x50, misc | 0x0300);
++}
++
+ /* List of quirks for OHCI */
+ static const struct pci_device_id ohci_pci_quirks[] = {
+ {
+--- a/drivers/usb/host/ohci-q.c
++++ b/drivers/usb/host/ohci-q.c
+@@ -49,9 +49,12 @@ __acquires(ohci->lock)
+ switch (usb_pipetype (urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--;
+- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+- && quirk_amdiso(ohci))
+- quirk_amd_pll(1);
++ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
++ if (quirk_amdiso(ohci))
++ quirk_amd_pll(1);
++ if (quirk_amdprefetch(ohci))
++ sb800_prefetch(ohci, 0);
++ }
+ break;
+ case PIPE_INTERRUPT:
+ ohci_to_hcd(ohci)->self.bandwidth_int_reqs--;
+@@ -680,9 +683,12 @@ static void td_submit_urb (
+ data + urb->iso_frame_desc [cnt].offset,
+ urb->iso_frame_desc [cnt].length, urb, cnt);
+ }
+- if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0
+- && quirk_amdiso(ohci))
+- quirk_amd_pll(0);
++ if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) {
++ if (quirk_amdiso(ohci))
++ quirk_amd_pll(0);
++ if (quirk_amdprefetch(ohci))
++ sb800_prefetch(ohci, 1);
++ }
+ periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
+ && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
+ break;
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -402,6 +402,7 @@ struct ohci_hcd {
+ #define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
+ #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
+ #define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
++#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
+ // there are also chip quirks/bugs in init logic
+
+ struct work_struct nec_work; /* Worker for NEC quirk */
+@@ -433,6 +434,10 @@ static inline int quirk_amdiso(struct oh
+ {
+ return ohci->flags & OHCI_QUIRK_AMD_ISO;
+ }
++static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
++{
++ return ohci->flags & OHCI_QUIRK_AMD_PREFETCH;
++}
+ #else
+ static inline int quirk_nec(struct ohci_hcd *ohci)
+ {
+@@ -446,6 +451,10 @@ static inline int quirk_amdiso(struct oh
+ {
+ return 0;
+ }
++static inline int quirk_amdprefetch(struct ohci_hcd *ohci)
++{
++ return 0;
++}
+ #endif
+
+ /* convert between an hcd pointer and the corresponding ohci_hcd */
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.667934007@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:49 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Oliver Neukum <oneukum@suse.de>,
+ Matthias Urlichs <smurf@smurf.noris.de>
+Subject: [17/20] USB: suspend/resume support for option driver
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=usb-suspend-resume-support-for-option-driver.patch
+Content-Length: 4791
+Lines: 168
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Oliver Neukum <oliver@neukum.org>
+
+commit 4901b2c34ecb6fc45909228ad269c8126efe4401 upstream.
+
+This patch implements suspend and resume methods for the
+option driver. With my hardware I can even suspend the system
+and keep up a connection for a short time.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Signed-Off-By: Matthias Urlichs <smurf@smurf.noris.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/option.c | 86 ++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 80 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_s
+ static int option_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
+ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
++static int option_suspend(struct usb_serial *serial, pm_message_t message);
++static int option_resume(struct usb_serial *serial);
+
+ /* Vendor and product IDs */
+ #define OPTION_VENDOR_ID 0x0AF0
+@@ -511,6 +513,8 @@ static struct usb_driver option_driver =
+ .name = "option",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
++ .suspend = usb_serial_suspend,
++ .resume = usb_serial_resume,
+ .id_table = option_ids,
+ .no_dynamic_id = 1,
+ };
+@@ -539,6 +543,8 @@ static struct usb_serial_driver option_1
+ .attach = option_startup,
+ .shutdown = option_shutdown,
+ .read_int_callback = option_instat_callback,
++ .suspend = option_suspend,
++ .resume = option_resume,
+ };
+
+ static int debug;
+@@ -809,10 +815,10 @@ static void option_instat_callback(struc
+ req_pkt->bRequestType, req_pkt->bRequest);
+ }
+ } else
+- dbg("%s: error %d", __func__, status);
++ err("%s: error %d", __func__, status);
+
+ /* Resubmit urb so we continue receiving IRQ data */
+- if (status != -ESHUTDOWN) {
++ if (status != -ESHUTDOWN && status != -ENOENT) {
+ urb->dev = serial->dev;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+@@ -831,7 +837,6 @@ static int option_write_room(struct tty_
+
+ portdata = usb_get_serial_port_data(port);
+
+-
+ for (i = 0; i < N_OUT_URB; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && !test_bit(i, &portdata->out_busy))
+@@ -1090,14 +1095,12 @@ bail_out_error:
+ return 1;
+ }
+
+-static void option_shutdown(struct usb_serial *serial)
++static void stop_read_write_urbs(struct usb_serial *serial)
+ {
+ int i, j;
+ struct usb_serial_port *port;
+ struct option_port_private *portdata;
+
+- dbg("%s", __func__);
+-
+ /* Stop reading/writing urbs */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+@@ -1107,6 +1110,17 @@ static void option_shutdown(struct usb_s
+ for (j = 0; j < N_OUT_URB; j++)
+ usb_kill_urb(portdata->out_urbs[j]);
+ }
++}
++
++static void option_shutdown(struct usb_serial *serial)
++{
++ int i, j;
++ struct usb_serial_port *port;
++ struct option_port_private *portdata;
++
++ dbg("%s", __func__);
++
++ stop_read_write_urbs(serial);
+
+ /* Now free them */
+ for (i = 0; i < serial->num_ports; ++i) {
+@@ -1137,6 +1151,66 @@ static void option_shutdown(struct usb_s
+ }
+ }
+
++static int option_suspend(struct usb_serial *serial, pm_message_t message)
++{
++ dbg("%s entered", __func__);
++ stop_read_write_urbs(serial);
++
++ return 0;
++}
++
++static int option_resume(struct usb_serial *serial)
++{
++ int err, i, j;
++ struct usb_serial_port *port;
++ struct urb *urb;
++ struct option_port_private *portdata;
++
++ dbg("%s entered", __func__);
++ /* get the interrupt URBs resubmitted unconditionally */
++ for (i = 0; i < serial->num_ports; i++) {
++ port = serial->port[i];
++ if (!port->interrupt_in_urb) {
++ dbg("%s: No interrupt URB for port %d\n", __func__, i);
++ continue;
++ }
++ port->interrupt_in_urb->dev = serial->dev;
++ err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
++ dbg("Submitted interrupt URB for port %d (result %d)", i, err);
++ if (err < 0) {
++ err("%s: Error %d for interrupt URB of port%d",
++ __func__, err, i);
++ return err;
++ }
++ }
++
++ for (i = 0; i < serial->num_ports; i++) {
++ /* walk all ports */
++ port = serial->port[i];
++ portdata = usb_get_serial_port_data(port);
++ mutex_lock(&port->mutex);
++
++ /* skip closed ports */
++ if (!port->port.count) {
++ mutex_unlock(&port->mutex);
++ continue;
++ }
++
++ for (j = 0; j < N_IN_URB; j++) {
++ urb = portdata->in_urbs[j];
++ err = usb_submit_urb(urb, GFP_NOIO);
++ if (err < 0) {
++ mutex_unlock(&port->mutex);
++ err("%s: Error %d for bulk URB %d",
++ __func__, err, i);
++ return err;
++ }
++ }
++ mutex_unlock(&port->mutex);
++ }
++ return 0;
++}
++
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_VERSION(DRIVER_VERSION);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:10 2009
+Message-Id: <20091206233210.832793005@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:50 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org,
+ Greg KH <greg@kroah.com>
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Rory Filer <rfiler@SierraWireless.com>,
+ USB list <linux-usb@vger.kernel.org>,
+ Alan Stern <stern@rowland.harvard.edu>
+Subject: [18/20] USB: usb-serial: replace shutdown with disconnect, release
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=usb-usb-serial-replace-shutdown-with-disconnect-release.patch
+Content-Length: 49323
+Lines: 1499
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+This is commit f9c99bb8b3a1ec81af68d484a551307326c2e933 back-ported to
+2.6.27.39.
+
+This patch (as1254-2) splits up the shutdown method of usb_serial_driver
+into a disconnect and a release method.
+
+The problem is that the usb-serial core was calling shutdown during
+disconnect handling, but drivers didn't expect it to be called until
+after all the open file references had been closed. The result was an
+oops when the close method tried to use memory that had been
+deallocated by shutdown.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Tested-by: Rory Filer <rfiler@SierraWireless.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/aircable.c | 5 +--
+ drivers/usb/serial/belkin_sa.c | 7 ++--
+ drivers/usb/serial/cp2101.c | 6 ++--
+ drivers/usb/serial/cyberjack.c | 20 ++++++++++----
+ drivers/usb/serial/cypress_m8.c | 11 +++----
+ drivers/usb/serial/digi_acceleport.c | 20 ++++++++++----
+ drivers/usb/serial/empeg.c | 8 -----
+ drivers/usb/serial/ftdi_sio.c | 14 ---------
+ drivers/usb/serial/garmin_gps.c | 16 +++++++++--
+ drivers/usb/serial/generic.c | 9 ++++--
+ drivers/usb/serial/io_edgeport.c | 29 ++++++++++++++------
+ drivers/usb/serial/io_tables.h | 12 +++++---
+ drivers/usb/serial/io_ti.c | 22 ++++++++++++---
+ drivers/usb/serial/ipaq.c | 7 ----
+ drivers/usb/serial/iuu_phoenix.c | 6 ++--
+ drivers/usb/serial/keyspan.c | 13 ++++++++-
+ drivers/usb/serial/keyspan.h | 12 +++++---
+ drivers/usb/serial/keyspan_pda.c | 4 +-
+ drivers/usb/serial/kl5kusb105.c | 39 +++++++++++++++------------
+ drivers/usb/serial/kobil_sct.c | 12 ++------
+ drivers/usb/serial/mct_u232.c | 13 +++------
+ drivers/usb/serial/mos7720.c | 9 ++----
+ drivers/usb/serial/mos7840.c | 48 ++++++++++++++++++++++++++++------
+ drivers/usb/serial/omninet.c | 19 ++++++++++---
+ drivers/usb/serial/option.c | 17 ++++++++----
+ drivers/usb/serial/oti6858.c | 7 ++--
+ drivers/usb/serial/pl2303.c | 5 +--
+ drivers/usb/serial/sierra.c | 28 +++++++++++++++++--
+ drivers/usb/serial/spcp8x5.c | 5 +--
+ drivers/usb/serial/ti_usb_3410_5052.c | 10 ++-----
+ drivers/usb/serial/usb-serial.c | 29 +++++++++-----------
+ drivers/usb/serial/visor.c | 13 +++------
+ drivers/usb/serial/whiteheat.c | 6 ++--
+ include/linux/usb/serial.h | 12 +++++---
+ 34 files changed, 298 insertions(+), 195 deletions(-)
+
+--- a/drivers/usb/serial/aircable.c
++++ b/drivers/usb/serial/aircable.c
+@@ -362,7 +362,7 @@ static int aircable_attach(struct usb_se
+ return 0;
+ }
+
+-static void aircable_shutdown(struct usb_serial *serial)
++static void aircable_release(struct usb_serial *serial)
+ {
+
+ struct usb_serial_port *port = serial->port[0];
+@@ -373,7 +373,6 @@ static void aircable_shutdown(struct usb
+ if (priv) {
+ serial_buf_free(priv->tx_buf);
+ serial_buf_free(priv->rx_buf);
+- usb_set_serial_port_data(port, NULL);
+ kfree(priv);
+ }
+ }
+@@ -598,7 +597,7 @@ static struct usb_serial_driver aircable
+ .num_ports = 1,
+ .attach = aircable_attach,
+ .probe = aircable_probe,
+- .shutdown = aircable_shutdown,
++ .release = aircable_release,
+ .write = aircable_write,
+ .write_room = aircable_write_room,
+ .write_bulk_callback = aircable_write_bulk_callback,
+--- a/drivers/usb/serial/belkin_sa.c
++++ b/drivers/usb/serial/belkin_sa.c
+@@ -90,7 +90,7 @@ static int debug;
+
+ /* function prototypes for a Belkin USB Serial Adapter F5U103 */
+ static int belkin_sa_startup(struct usb_serial *serial);
+-static void belkin_sa_shutdown(struct usb_serial *serial);
++static void belkin_sa_release(struct usb_serial *serial);
+ static int belkin_sa_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void belkin_sa_close(struct tty_struct *tty,
+@@ -143,7 +143,7 @@ static struct usb_serial_driver belkin_d
+ .tiocmget = belkin_sa_tiocmget,
+ .tiocmset = belkin_sa_tiocmset,
+ .attach = belkin_sa_startup,
+- .shutdown = belkin_sa_shutdown,
++ .release = belkin_sa_release,
+ };
+
+
+@@ -198,14 +198,13 @@ static int belkin_sa_startup(struct usb_
+ }
+
+
+-static void belkin_sa_shutdown(struct usb_serial *serial)
++static void belkin_sa_release(struct usb_serial *serial)
+ {
+ struct belkin_sa_private *priv;
+ int i;
+
+ dbg("%s", __func__);
+
+- /* stop reads and writes on all ports */
+ for (i = 0; i < serial->num_ports; ++i) {
+ /* My special items, the standard routines free my urbs */
+ priv = usb_get_serial_port_data(serial->port[i]);
+--- a/drivers/usb/serial/cp2101.c
++++ b/drivers/usb/serial/cp2101.c
+@@ -50,7 +50,7 @@ static int cp2101_tiocmset(struct tty_st
+ unsigned int, unsigned int);
+ static void cp2101_break_ctl(struct tty_struct *, int);
+ static int cp2101_startup(struct usb_serial *);
+-static void cp2101_shutdown(struct usb_serial *);
++static void cp2101_disconnect(struct usb_serial *);
+
+
+ static int debug;
+@@ -125,7 +125,7 @@ static struct usb_serial_driver cp2101_d
+ .tiocmget = cp2101_tiocmget,
+ .tiocmset = cp2101_tiocmset,
+ .attach = cp2101_startup,
+- .shutdown = cp2101_shutdown,
++ .disconnect = cp2101_disconnect,
+ };
+
+ /* Config request types */
+@@ -727,7 +727,7 @@ static int cp2101_startup(struct usb_ser
+ return 0;
+ }
+
+-static void cp2101_shutdown(struct usb_serial *serial)
++static void cp2101_disconnect(struct usb_serial *serial)
+ {
+ int i;
+
+--- a/drivers/usb/serial/cyberjack.c
++++ b/drivers/usb/serial/cyberjack.c
+@@ -58,7 +58,8 @@ static int debug;
+
+ /* Function prototypes */
+ static int cyberjack_startup(struct usb_serial *serial);
+-static void cyberjack_shutdown(struct usb_serial *serial);
++static void cyberjack_disconnect(struct usb_serial *serial);
++static void cyberjack_release(struct usb_serial *serial);
+ static int cyberjack_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void cyberjack_close(struct tty_struct *tty,
+@@ -95,7 +96,8 @@ static struct usb_serial_driver cyberjac
+ .id_table = id_table,
+ .num_ports = 1,
+ .attach = cyberjack_startup,
+- .shutdown = cyberjack_shutdown,
++ .disconnect = cyberjack_disconnect,
++ .release = cyberjack_release,
+ .open = cyberjack_open,
+ .close = cyberjack_close,
+ .write = cyberjack_write,
+@@ -148,17 +150,25 @@ static int cyberjack_startup(struct usb_
+ return 0;
+ }
+
+-static void cyberjack_shutdown(struct usb_serial *serial)
++static void cyberjack_disconnect(struct usb_serial *serial)
+ {
+ int i;
+
+ dbg("%s", __func__);
+
+- for (i = 0; i < serial->num_ports; ++i) {
++ for (i = 0; i < serial->num_ports; ++i)
+ usb_kill_urb(serial->port[i]->interrupt_in_urb);
++}
++
++static void cyberjack_release(struct usb_serial *serial)
++{
++ int i;
++
++ dbg("%s", __func__);
++
++ for (i = 0; i < serial->num_ports; ++i) {
+ /* My special items, the standard routines free my urbs */
+ kfree(usb_get_serial_port_data(serial->port[i]));
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -171,7 +171,7 @@ struct cypress_buf {
+ static int cypress_earthmate_startup(struct usb_serial *serial);
+ static int cypress_hidcom_startup(struct usb_serial *serial);
+ static int cypress_ca42v2_startup(struct usb_serial *serial);
+-static void cypress_shutdown(struct usb_serial *serial);
++static void cypress_release(struct usb_serial *serial);
+ static int cypress_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void cypress_close(struct tty_struct *tty,
+@@ -215,7 +215,7 @@ static struct usb_serial_driver cypress_
+ .id_table = id_table_earthmate,
+ .num_ports = 1,
+ .attach = cypress_earthmate_startup,
+- .shutdown = cypress_shutdown,
++ .release = cypress_release,
+ .open = cypress_open,
+ .close = cypress_close,
+ .write = cypress_write,
+@@ -241,7 +241,7 @@ static struct usb_serial_driver cypress_
+ .id_table = id_table_cyphidcomrs232,
+ .num_ports = 1,
+ .attach = cypress_hidcom_startup,
+- .shutdown = cypress_shutdown,
++ .release = cypress_release,
+ .open = cypress_open,
+ .close = cypress_close,
+ .write = cypress_write,
+@@ -267,7 +267,7 @@ static struct usb_serial_driver cypress_
+ .id_table = id_table_nokiaca42v2,
+ .num_ports = 1,
+ .attach = cypress_ca42v2_startup,
+- .shutdown = cypress_shutdown,
++ .release = cypress_release,
+ .open = cypress_open,
+ .close = cypress_close,
+ .write = cypress_write,
+@@ -612,7 +612,7 @@ static int cypress_ca42v2_startup(struct
+ } /* cypress_ca42v2_startup */
+
+
+-static void cypress_shutdown(struct usb_serial *serial)
++static void cypress_release(struct usb_serial *serial)
+ {
+ struct cypress_private *priv;
+
+@@ -625,7 +625,6 @@ static void cypress_shutdown(struct usb_
+ if (priv) {
+ cypress_buf_free(priv->buf);
+ kfree(priv);
+- usb_set_serial_port_data(serial->port[0], NULL);
+ }
+ }
+
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -460,7 +460,8 @@ static void digi_close(struct tty_struct
+ struct file *filp);
+ static int digi_startup_device(struct usb_serial *serial);
+ static int digi_startup(struct usb_serial *serial);
+-static void digi_shutdown(struct usb_serial *serial);
++static void digi_disconnect(struct usb_serial *serial);
++static void digi_release(struct usb_serial *serial);
+ static void digi_read_bulk_callback(struct urb *urb);
+ static int digi_read_inb_callback(struct urb *urb);
+ static int digi_read_oob_callback(struct urb *urb);
+@@ -522,7 +523,8 @@ static struct usb_serial_driver digi_acc
+ .tiocmget = digi_tiocmget,
+ .tiocmset = digi_tiocmset,
+ .attach = digi_startup,
+- .shutdown = digi_shutdown,
++ .disconnect = digi_disconnect,
++ .release = digi_release,
+ };
+
+ static struct usb_serial_driver digi_acceleport_4_device = {
+@@ -548,7 +550,8 @@ static struct usb_serial_driver digi_acc
+ .tiocmget = digi_tiocmget,
+ .tiocmset = digi_tiocmset,
+ .attach = digi_startup,
+- .shutdown = digi_shutdown,
++ .disconnect = digi_disconnect,
++ .release = digi_release,
+ };
+
+
+@@ -1586,16 +1589,23 @@ static int digi_startup(struct usb_seria
+ }
+
+
+-static void digi_shutdown(struct usb_serial *serial)
++static void digi_disconnect(struct usb_serial *serial)
+ {
+ int i;
+- dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt());
++ dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt());
+
+ /* stop reads and writes on all ports */
+ for (i = 0; i < serial->type->num_ports + 1; i++) {
+ usb_kill_urb(serial->port[i]->read_urb);
+ usb_kill_urb(serial->port[i]->write_urb);
+ }
++}
++
++
++static void digi_release(struct usb_serial *serial)
++{
++ int i;
++ dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt());
+
+ /* free the private data structures for all ports */
+ /* number of regular ports + 1 for the out-of-band port */
+--- a/drivers/usb/serial/empeg.c
++++ b/drivers/usb/serial/empeg.c
+@@ -92,7 +92,6 @@ static int empeg_chars_in_buffer(struct
+ static void empeg_throttle(struct tty_struct *tty);
+ static void empeg_unthrottle(struct tty_struct *tty);
+ static int empeg_startup(struct usb_serial *serial);
+-static void empeg_shutdown(struct usb_serial *serial);
+ static void empeg_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios);
+ static void empeg_write_bulk_callback(struct urb *urb);
+@@ -126,7 +125,6 @@ static struct usb_serial_driver empeg_de
+ .throttle = empeg_throttle,
+ .unthrottle = empeg_unthrottle,
+ .attach = empeg_startup,
+- .shutdown = empeg_shutdown,
+ .set_termios = empeg_set_termios,
+ .write = empeg_write,
+ .write_room = empeg_write_room,
+@@ -429,12 +427,6 @@ static int empeg_startup(struct usb_ser
+ }
+
+
+-static void empeg_shutdown(struct usb_serial *serial)
+-{
+- dbg("%s", __func__);
+-}
+-
+-
+ static void empeg_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+ {
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -708,7 +708,6 @@ static const char *ftdi_chip_name[] = {
+ /* function prototypes for a FTDI serial converter */
+ static int ftdi_sio_probe(struct usb_serial *serial,
+ const struct usb_device_id *id);
+-static void ftdi_shutdown(struct usb_serial *serial);
+ static int ftdi_sio_port_probe(struct usb_serial_port *port);
+ static int ftdi_sio_port_remove(struct usb_serial_port *port);
+ static int ftdi_open(struct tty_struct *tty,
+@@ -764,7 +763,6 @@ static struct usb_serial_driver ftdi_sio
+ .ioctl = ftdi_ioctl,
+ .set_termios = ftdi_set_termios,
+ .break_ctl = ftdi_break_ctl,
+- .shutdown = ftdi_shutdown,
+ };
+
+
+@@ -1442,18 +1440,6 @@ static int ftdi_mtxorb_hack_setup(struct
+ return 0;
+ }
+
+-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
+- * it is called when the usb device is disconnected
+- *
+- * usbserial:usb_serial_disconnect
+- * calls __serial_close for each open of the port
+- * shutdown is called then (ie ftdi_shutdown)
+- */
+-static void ftdi_shutdown(struct usb_serial *serial)
+-{
+- dbg("%s", __func__);
+-}
+-
+ static int ftdi_sio_port_remove(struct usb_serial_port *port)
+ {
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+--- a/drivers/usb/serial/garmin_gps.c
++++ b/drivers/usb/serial/garmin_gps.c
+@@ -1527,7 +1527,7 @@ static int garmin_attach(struct usb_seri
+ }
+
+
+-static void garmin_shutdown(struct usb_serial *serial)
++static void garmin_disconnect(struct usb_serial *serial)
+ {
+ struct usb_serial_port *port = serial->port[0];
+ struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
+@@ -1536,8 +1536,17 @@ static void garmin_shutdown(struct usb_s
+
+ usb_kill_urb(port->interrupt_in_urb);
+ del_timer_sync(&garmin_data_p->timer);
++}
++
++
++static void garmin_release(struct usb_serial *serial)
++{
++ struct usb_serial_port *port = serial->port[0];
++ struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
++
++ dbg("%s", __func__);
++
+ kfree(garmin_data_p);
+- usb_set_serial_port_data(port, NULL);
+ }
+
+
+@@ -1556,7 +1565,8 @@ static struct usb_serial_driver garmin_d
+ .throttle = garmin_throttle,
+ .unthrottle = garmin_unthrottle,
+ .attach = garmin_attach,
+- .shutdown = garmin_shutdown,
++ .disconnect = garmin_disconnect,
++ .release = garmin_release,
+ .write = garmin_write,
+ .write_room = garmin_write_room,
+ .write_bulk_callback = garmin_write_bulk_callback,
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -63,7 +63,8 @@ struct usb_serial_driver usb_serial_gene
+ .id_table = generic_device_ids,
+ .usb_driver = &generic_driver,
+ .num_ports = 1,
+- .shutdown = usb_serial_generic_shutdown,
++ .disconnect = usb_serial_generic_disconnect,
++ .release = usb_serial_generic_release,
+ .throttle = usb_serial_generic_throttle,
+ .unthrottle = usb_serial_generic_unthrottle,
+ .resume = usb_serial_generic_resume,
+@@ -419,7 +420,7 @@ void usb_serial_generic_unthrottle(struc
+ }
+ }
+
+-void usb_serial_generic_shutdown(struct usb_serial *serial)
++void usb_serial_generic_disconnect(struct usb_serial *serial)
+ {
+ int i;
+
+@@ -430,3 +431,7 @@ void usb_serial_generic_shutdown(struct
+ generic_cleanup(serial->port[i]);
+ }
+
++void usb_serial_generic_release(struct usb_serial *serial)
++{
++ dbg("%s", __func__);
++}
+--- a/drivers/usb/serial/io_edgeport.c
++++ b/drivers/usb/serial/io_edgeport.c
+@@ -225,7 +225,8 @@ static int edge_tiocmget(struct tty_str
+ static int edge_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
+ static int edge_startup(struct usb_serial *serial);
+-static void edge_shutdown(struct usb_serial *serial);
++static void edge_disconnect(struct usb_serial *serial);
++static void edge_release(struct usb_serial *serial);
+
+ #include "io_tables.h" /* all of the devices that this driver supports */
+
+@@ -3178,21 +3179,16 @@ static int edge_startup(struct usb_seria
+
+
+ /****************************************************************************
+- * edge_shutdown
++ * edge_disconnect
+ * This function is called whenever the device is removed from the usb bus.
+ ****************************************************************************/
+-static void edge_shutdown(struct usb_serial *serial)
++static void edge_disconnect(struct usb_serial *serial)
+ {
+ struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
+- int i;
+
+ dbg("%s", __func__);
+
+ /* stop reads and writes on all ports */
+- for (i = 0; i < serial->num_ports; ++i) {
+- kfree(usb_get_serial_port_data(serial->port[i]));
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+ /* free up our endpoint stuff */
+ if (edge_serial->is_epic) {
+ usb_kill_urb(edge_serial->interrupt_read_urb);
+@@ -3203,9 +3199,24 @@ static void edge_shutdown(struct usb_ser
+ usb_free_urb(edge_serial->read_urb);
+ kfree(edge_serial->bulk_in_buffer);
+ }
++}
++
++
++/****************************************************************************
++ * edge_release
++ * This function is called when the device structure is deallocated.
++ ****************************************************************************/
++static void edge_release(struct usb_serial *serial)
++{
++ struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
++ int i;
++
++ dbg("%s", __func__);
++
++ for (i = 0; i < serial->num_ports; ++i)
++ kfree(usb_get_serial_port_data(serial->port[i]));
+
+ kfree(edge_serial);
+- usb_set_serial_data(serial, NULL);
+ }
+
+
+--- a/drivers/usb/serial/io_tables.h
++++ b/drivers/usb/serial/io_tables.h
+@@ -117,7 +117,8 @@ static struct usb_serial_driver edgeport
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+@@ -145,7 +146,8 @@ static struct usb_serial_driver edgeport
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+@@ -173,7 +175,8 @@ static struct usb_serial_driver edgeport
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+@@ -200,7 +203,8 @@ static struct usb_serial_driver epic_dev
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -2652,7 +2652,7 @@ cleanup:
+ return -ENOMEM;
+ }
+
+-static void edge_shutdown(struct usb_serial *serial)
++static void edge_disconnect(struct usb_serial *serial)
+ {
+ int i;
+ struct edgeport_port *edge_port;
+@@ -2662,12 +2662,22 @@ static void edge_shutdown(struct usb_ser
+ for (i = 0; i < serial->num_ports; ++i) {
+ edge_port = usb_get_serial_port_data(serial->port[i]);
+ edge_remove_sysfs_attrs(edge_port->port);
++ }
++}
++
++static void edge_release(struct usb_serial *serial)
++{
++ int i;
++ struct edgeport_port *edge_port;
++
++ dbg("%s", __func__);
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ edge_port = usb_get_serial_port_data(serial->port[i]);
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ kfree(usb_get_serial_data(serial));
+- usb_set_serial_data(serial, NULL);
+ }
+
+
+@@ -2904,7 +2914,8 @@ static struct usb_serial_driver edgeport
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .port_probe = edge_create_sysfs_attrs,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+@@ -2933,7 +2944,8 @@ static struct usb_serial_driver edgeport
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+- .shutdown = edge_shutdown,
++ .disconnect = edge_disconnect,
++ .release = edge_release,
+ .port_probe = edge_create_sysfs_attrs,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+--- a/drivers/usb/serial/ipaq.c
++++ b/drivers/usb/serial/ipaq.c
+@@ -79,7 +79,6 @@ static int ipaq_open(struct tty_struct
+ static void ipaq_close(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static int ipaq_startup(struct usb_serial *serial);
+-static void ipaq_shutdown(struct usb_serial *serial);
+ static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+ static int ipaq_write_bulk(struct usb_serial_port *port,
+@@ -581,7 +580,6 @@ static struct usb_serial_driver ipaq_dev
+ .open = ipaq_open,
+ .close = ipaq_close,
+ .attach = ipaq_startup,
+- .shutdown = ipaq_shutdown,
+ .write = ipaq_write,
+ .write_room = ipaq_write_room,
+ .chars_in_buffer = ipaq_chars_in_buffer,
+@@ -957,11 +955,6 @@ static int ipaq_startup(struct usb_seria
+ return usb_reset_configuration(serial->dev);
+ }
+
+-static void ipaq_shutdown(struct usb_serial *serial)
+-{
+- dbg("%s", __func__);
+-}
+-
+ static int __init ipaq_init(void)
+ {
+ int retval;
+--- a/drivers/usb/serial/iuu_phoenix.c
++++ b/drivers/usb/serial/iuu_phoenix.c
+@@ -122,8 +122,8 @@ static int iuu_startup(struct usb_serial
+ return 0;
+ }
+
+-/* Shutdown function */
+-static void iuu_shutdown(struct usb_serial *serial)
++/* Release function */
++static void iuu_release(struct usb_serial *serial)
+ {
+ struct usb_serial_port *port = serial->port[0];
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+@@ -1171,7 +1171,7 @@ static struct usb_serial_driver iuu_devi
+ .tiocmget = iuu_tiocmget,
+ .tiocmset = iuu_tiocmset,
+ .attach = iuu_startup,
+- .shutdown = iuu_shutdown,
++ .release = iuu_release,
+ };
+
+ static int __init iuu_init(void)
+--- a/drivers/usb/serial/keyspan.c
++++ b/drivers/usb/serial/keyspan.c
+@@ -2678,7 +2678,7 @@ static int keyspan_startup(struct usb_se
+ return 0;
+ }
+
+-static void keyspan_shutdown(struct usb_serial *serial)
++static void keyspan_disconnect(struct usb_serial *serial)
+ {
+ int i, j;
+ struct usb_serial_port *port;
+@@ -2718,6 +2718,17 @@ static void keyspan_shutdown(struct usb_
+ usb_free_urb(p_priv->out_urbs[j]);
+ }
+ }
++}
++
++static void keyspan_release(struct usb_serial *serial)
++{
++ int i;
++ struct usb_serial_port *port;
++ struct keyspan_serial_private *s_priv;
++
++ dbg("%s", __func__);
++
++ s_priv = usb_get_serial_data(serial);
+
+ /* dbg("Freeing serial->private."); */
+ kfree(s_priv);
+--- a/drivers/usb/serial/keyspan.h
++++ b/drivers/usb/serial/keyspan.h
+@@ -42,7 +42,8 @@ static void keyspan_close (struct tty_s
+ struct usb_serial_port *port,
+ struct file *filp);
+ static int keyspan_startup (struct usb_serial *serial);
+-static void keyspan_shutdown (struct usb_serial *serial);
++static void keyspan_disconnect (struct usb_serial *serial);
++static void keyspan_release (struct usb_serial *serial);
+ static int keyspan_write_room (struct tty_struct *tty);
+
+ static int keyspan_write (struct tty_struct *tty,
+@@ -569,7 +570,8 @@ static struct usb_serial_driver keyspan_
+ .tiocmget = keyspan_tiocmget,
+ .tiocmset = keyspan_tiocmset,
+ .attach = keyspan_startup,
+- .shutdown = keyspan_shutdown,
++ .disconnect = keyspan_disconnect,
++ .release = keyspan_release,
+ };
+
+ static struct usb_serial_driver keyspan_2port_device = {
+@@ -589,7 +591,8 @@ static struct usb_serial_driver keyspan_
+ .tiocmget = keyspan_tiocmget,
+ .tiocmset = keyspan_tiocmset,
+ .attach = keyspan_startup,
+- .shutdown = keyspan_shutdown,
++ .disconnect = keyspan_disconnect,
++ .release = keyspan_release,
+ };
+
+ static struct usb_serial_driver keyspan_4port_device = {
+@@ -609,7 +612,8 @@ static struct usb_serial_driver keyspan_
+ .tiocmget = keyspan_tiocmget,
+ .tiocmset = keyspan_tiocmset,
+ .attach = keyspan_startup,
+- .shutdown = keyspan_shutdown,
++ .disconnect = keyspan_disconnect,
++ .release = keyspan_release,
+ };
+
+ #endif
+--- a/drivers/usb/serial/keyspan_pda.c
++++ b/drivers/usb/serial/keyspan_pda.c
+@@ -789,7 +789,7 @@ static int keyspan_pda_startup(struct us
+ return 0;
+ }
+
+-static void keyspan_pda_shutdown(struct usb_serial *serial)
++static void keyspan_pda_release(struct usb_serial *serial)
+ {
+ dbg("%s", __func__);
+
+@@ -847,7 +847,7 @@ static struct usb_serial_driver keyspan_
+ .tiocmget = keyspan_pda_tiocmget,
+ .tiocmset = keyspan_pda_tiocmset,
+ .attach = keyspan_pda_startup,
+- .shutdown = keyspan_pda_shutdown,
++ .release = keyspan_pda_release,
+ };
+
+
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -73,7 +73,8 @@ static int debug;
+ * Function prototypes
+ */
+ static int klsi_105_startup(struct usb_serial *serial);
+-static void klsi_105_shutdown(struct usb_serial *serial);
++static void klsi_105_disconnect(struct usb_serial *serial);
++static void klsi_105_release(struct usb_serial *serial);
+ static int klsi_105_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void klsi_105_close(struct tty_struct *tty,
+@@ -132,7 +133,8 @@ static struct usb_serial_driver kl5kusb1
+ .tiocmget = klsi_105_tiocmget,
+ .tiocmset = klsi_105_tiocmset,
+ .attach = klsi_105_startup,
+- .shutdown = klsi_105_shutdown,
++ .disconnect = klsi_105_disconnect,
++ .release = klsi_105_release,
+ .throttle = klsi_105_throttle,
+ .unthrottle = klsi_105_unthrottle,
+ };
+@@ -314,7 +316,7 @@ err_cleanup:
+ } /* klsi_105_startup */
+
+
+-static void klsi_105_shutdown(struct usb_serial *serial)
++static void klsi_105_disconnect(struct usb_serial *serial)
+ {
+ int i;
+
+@@ -324,33 +326,36 @@ static void klsi_105_shutdown(struct usb
+ for (i = 0; i < serial->num_ports; ++i) {
+ struct klsi_105_private *priv =
+ usb_get_serial_port_data(serial->port[i]);
+- unsigned long flags;
+
+ if (priv) {
+ /* kill our write urb pool */
+ int j;
+ struct urb **write_urbs = priv->write_urb_pool;
+- spin_lock_irqsave(&priv->lock, flags);
+
+ for (j = 0; j < NUM_URBS; j++) {
+ if (write_urbs[j]) {
+- /* FIXME - uncomment the following
+- * usb_kill_urb call when the host
+- * controllers get fixed to set
+- * urb->dev = NULL after the urb is
+- * finished. Otherwise this call
+- * oopses. */
+- /* usb_kill_urb(write_urbs[j]); */
+- kfree(write_urbs[j]->transfer_buffer);
++ usb_kill_urb(write_urbs[j]);
+ usb_free_urb(write_urbs[j]);
+ }
+ }
+- spin_unlock_irqrestore(&priv->lock, flags);
+- kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+-} /* klsi_105_shutdown */
++} /* klsi_105_disconnect */
++
++
++static void klsi_105_release(struct usb_serial *serial)
++{
++ int i;
++
++ dbg("%s", __func__);
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ struct klsi_105_private *priv =
++ usb_get_serial_port_data(serial->port[i]);
++
++ kfree(priv);
++ }
++} /* klsi_105_release */
+
+ static int klsi_105_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp)
+--- a/drivers/usb/serial/kobil_sct.c
++++ b/drivers/usb/serial/kobil_sct.c
+@@ -69,7 +69,7 @@ static int debug;
+
+ /* Function prototypes */
+ static int kobil_startup(struct usb_serial *serial);
+-static void kobil_shutdown(struct usb_serial *serial);
++static void kobil_release(struct usb_serial *serial);
+ static int kobil_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void kobil_close(struct tty_struct *tty, struct usb_serial_port *port,
+@@ -118,7 +118,7 @@ static struct usb_serial_driver kobil_de
+ .id_table = id_table,
+ .num_ports = 1,
+ .attach = kobil_startup,
+- .shutdown = kobil_shutdown,
++ .release = kobil_release,
+ .ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
+ .tiocmget = kobil_tiocmget,
+@@ -202,17 +202,13 @@ static int kobil_startup(struct usb_seri
+ }
+
+
+-static void kobil_shutdown(struct usb_serial *serial)
++static void kobil_release(struct usb_serial *serial)
+ {
+ int i;
+ dbg("%s - port %d", __func__, serial->port[0]->number);
+
+- for (i = 0; i < serial->num_ports; ++i) {
+- while (serial->port[i]->port.count > 0)
+- kobil_close(NULL, serial->port[i], NULL);
++ for (i = 0; i < serial->num_ports; ++i)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+ }
+
+
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -92,7 +92,7 @@ static int debug;
+ * Function prototypes
+ */
+ static int mct_u232_startup(struct usb_serial *serial);
+-static void mct_u232_shutdown(struct usb_serial *serial);
++static void mct_u232_release(struct usb_serial *serial);
+ static int mct_u232_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void mct_u232_close(struct tty_struct *tty,
+@@ -148,7 +148,7 @@ static struct usb_serial_driver mct_u232
+ .tiocmget = mct_u232_tiocmget,
+ .tiocmset = mct_u232_tiocmset,
+ .attach = mct_u232_startup,
+- .shutdown = mct_u232_shutdown,
++ .release = mct_u232_release,
+ };
+
+
+@@ -401,7 +401,7 @@ static int mct_u232_startup(struct usb_s
+ } /* mct_u232_startup */
+
+
+-static void mct_u232_shutdown(struct usb_serial *serial)
++static void mct_u232_release(struct usb_serial *serial)
+ {
+ struct mct_u232_private *priv;
+ int i;
+@@ -411,12 +411,9 @@ static void mct_u232_shutdown(struct usb
+ for (i = 0; i < serial->num_ports; ++i) {
+ /* My special items, the standard routines free my urbs */
+ priv = usb_get_serial_port_data(serial->port[i]);
+- if (priv) {
+- usb_set_serial_port_data(serial->port[i], NULL);
+- kfree(priv);
+- }
++ kfree(priv);
+ }
+-} /* mct_u232_shutdown */
++} /* mct_u232_release */
+
+ static int mct_u232_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp)
+--- a/drivers/usb/serial/mos7720.c
++++ b/drivers/usb/serial/mos7720.c
+@@ -1547,19 +1547,16 @@ static int mos7720_startup(struct usb_se
+ return 0;
+ }
+
+-static void mos7720_shutdown(struct usb_serial *serial)
++static void mos7720_release(struct usb_serial *serial)
+ {
+ int i;
+
+ /* free private structure allocated for serial port */
+- for (i = 0; i < serial->num_ports; ++i) {
++ for (i = 0; i < serial->num_ports; ++i)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+- usb_set_serial_port_data(serial->port[i], NULL);
+- }
+
+ /* free private structure allocated for serial device */
+ kfree(usb_get_serial_data(serial));
+- usb_set_serial_data(serial, NULL);
+ }
+
+ static struct usb_driver usb_driver = {
+@@ -1584,7 +1581,7 @@ static struct usb_serial_driver moschip7
+ .throttle = mos7720_throttle,
+ .unthrottle = mos7720_unthrottle,
+ .attach = mos7720_startup,
+- .shutdown = mos7720_shutdown,
++ .release = mos7720_release,
+ .ioctl = mos7720_ioctl,
+ .set_termios = mos7720_set_termios,
+ .write = mos7720_write,
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -2643,16 +2643,16 @@ error:
+ }
+
+ /****************************************************************************
+- * mos7840_shutdown
++ * mos7840_disconnect
+ * This function is called whenever the device is removed from the usb bus.
+ ****************************************************************************/
+
+-static void mos7840_shutdown(struct usb_serial *serial)
++static void mos7840_disconnect(struct usb_serial *serial)
+ {
+ int i;
+ unsigned long flags;
+ struct moschip_port *mos7840_port;
+- dbg("%s \n", " shutdown :entering..........");
++ dbg("%s\n", " disconnect :entering..........");
+
+ if (!serial) {
+ dbg("%s", "Invalid Handler \n");
+@@ -2670,10 +2670,41 @@ static void mos7840_shutdown(struct usb_
+ mos7840_port->zombie = 1;
+ spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
+ usb_kill_urb(mos7840_port->control_urb);
+- kfree(mos7840_port->ctrl_buf);
+- kfree(mos7840_port->dr);
+- kfree(mos7840_port);
+- mos7840_set_port_private(serial->port[i], NULL);
++ }
++
++ dbg("%s\n", "Thank u ::");
++
++}
++
++/****************************************************************************
++ * mos7840_release
++ * This function is called when the usb_serial structure is freed.
++ ****************************************************************************/
++
++static void mos7840_release(struct usb_serial *serial)
++{
++ int i;
++ struct moschip_port *mos7840_port;
++ dbg("%s\n", " release :entering..........");
++
++ if (!serial) {
++ dbg("%s", "Invalid Handler");
++ return;
++ }
++
++ /* check for the ports to be closed,close the ports and disconnect */
++
++ /* free private structure allocated for serial port *
++ * stop reads and writes on all ports */
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ mos7840_port = mos7840_get_port_private(serial->port[i]);
++ dbg("mos7840_port %d = %p", i, mos7840_port);
++ if (mos7840_port) {
++ kfree(mos7840_port->ctrl_buf);
++ kfree(mos7840_port->dr);
++ kfree(mos7840_port);
++ }
+ }
+
+ dbg("%s\n", "Thank u :: ");
+@@ -2714,7 +2745,8 @@ static struct usb_serial_driver moschip7
+ .tiocmget = mos7840_tiocmget,
+ .tiocmset = mos7840_tiocmset,
+ .attach = mos7840_startup,
+- .shutdown = mos7840_shutdown,
++ .disconnect = mos7840_disconnect,
++ .release = mos7840_release,
+ .read_bulk_callback = mos7840_bulk_in_callback,
+ .read_int_callback = mos7840_interrupt_callback,
+ };
+--- a/drivers/usb/serial/omninet.c
++++ b/drivers/usb/serial/omninet.c
+@@ -73,7 +73,8 @@ static void omninet_write_bulk_callback(
+ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+ static int omninet_write_room(struct tty_struct *tty);
+-static void omninet_shutdown(struct usb_serial *serial);
++static void omninet_disconnect(struct usb_serial *serial);
++static void omninet_release(struct usb_serial *serial);
+ static int omninet_attach(struct usb_serial *serial);
+
+ static struct usb_device_id id_table[] = {
+@@ -109,7 +110,8 @@ static struct usb_serial_driver zyxel_om
+ .write_room = omninet_write_room,
+ .read_bulk_callback = omninet_read_bulk_callback,
+ .write_bulk_callback = omninet_write_bulk_callback,
+- .shutdown = omninet_shutdown,
++ .disconnect = omninet_disconnect,
++ .release = omninet_release,
+ };
+
+
+@@ -342,13 +344,22 @@ static void omninet_write_bulk_callback(
+ }
+
+
+-static void omninet_shutdown(struct usb_serial *serial)
++static void omninet_disconnect(struct usb_serial *serial)
+ {
+ struct usb_serial_port *wport = serial->port[1];
+- struct usb_serial_port *port = serial->port[0];
++
+ dbg("%s", __func__);
+
+ usb_kill_urb(wport->write_urb);
++}
++
++
++static void omninet_release(struct usb_serial *serial)
++{
++ struct usb_serial_port *port = serial->port[0];
++
++ dbg("%s", __func__);
++
+ kfree(usb_get_serial_port_data(port));
+ }
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -48,7 +48,8 @@ static int option_open(struct tty_struc
+ static void option_close(struct tty_struct *tty, struct usb_serial_port *port,
+ struct file *filp);
+ static int option_startup(struct usb_serial *serial);
+-static void option_shutdown(struct usb_serial *serial);
++static void option_disconnect(struct usb_serial *serial);
++static void option_release(struct usb_serial *serial);
+ static int option_write_room(struct tty_struct *tty);
+
+ static void option_instat_callback(struct urb *urb);
+@@ -541,7 +542,8 @@ static struct usb_serial_driver option_1
+ .tiocmget = option_tiocmget,
+ .tiocmset = option_tiocmset,
+ .attach = option_startup,
+- .shutdown = option_shutdown,
++ .disconnect = option_disconnect,
++ .release = option_release,
+ .read_int_callback = option_instat_callback,
+ .suspend = option_suspend,
+ .resume = option_resume,
+@@ -1112,7 +1114,14 @@ static void stop_read_write_urbs(struct
+ }
+ }
+
+-static void option_shutdown(struct usb_serial *serial)
++static void option_disconnect(struct usb_serial *serial)
++{
++ dbg("%s", __func__);
++
++ stop_read_write_urbs(serial);
++}
++
++static void option_release(struct usb_serial *serial)
+ {
+ int i, j;
+ struct usb_serial_port *port;
+@@ -1120,8 +1129,6 @@ static void option_shutdown(struct usb_s
+
+ dbg("%s", __func__);
+
+- stop_read_write_urbs(serial);
+-
+ /* Now free them */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+--- a/drivers/usb/serial/oti6858.c
++++ b/drivers/usb/serial/oti6858.c
+@@ -160,7 +160,7 @@ static int oti6858_tiocmget(struct tty_s
+ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
+ static int oti6858_startup(struct usb_serial *serial);
+-static void oti6858_shutdown(struct usb_serial *serial);
++static void oti6858_release(struct usb_serial *serial);
+
+ /* functions operating on buffers */
+ static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
+@@ -195,7 +195,7 @@ static struct usb_serial_driver oti6858_
+ .write_room = oti6858_write_room,
+ .chars_in_buffer = oti6858_chars_in_buffer,
+ .attach = oti6858_startup,
+- .shutdown = oti6858_shutdown,
++ .release = oti6858_release,
+ };
+
+ struct oti6858_private {
+@@ -833,7 +833,7 @@ static int oti6858_ioctl(struct tty_stru
+ }
+
+
+-static void oti6858_shutdown(struct usb_serial *serial)
++static void oti6858_release(struct usb_serial *serial)
+ {
+ struct oti6858_private *priv;
+ int i;
+@@ -845,7 +845,6 @@ static void oti6858_shutdown(struct usb_
+ if (priv) {
+ oti6858_buf_free(priv->buf);
+ kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+ }
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -905,7 +905,7 @@ static void pl2303_break_ctl(struct tty_
+ dbg("%s - error sending break = %d", __func__, result);
+ }
+
+-static void pl2303_shutdown(struct usb_serial *serial)
++static void pl2303_release(struct usb_serial *serial)
+ {
+ int i;
+ struct pl2303_private *priv;
+@@ -917,7 +917,6 @@ static void pl2303_shutdown(struct usb_s
+ if (priv) {
+ pl2303_buf_free(priv->buf);
+ kfree(priv);
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+ }
+@@ -1145,7 +1144,7 @@ static struct usb_serial_driver pl2303_d
+ .write_room = pl2303_write_room,
+ .chars_in_buffer = pl2303_chars_in_buffer,
+ .attach = pl2303_startup,
+- .shutdown = pl2303_shutdown,
++ .release = pl2303_release,
+ };
+
+ static int __init pl2303_init(void)
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -677,7 +677,7 @@ static int sierra_startup(struct usb_ser
+ return 0;
+ }
+
+-static void sierra_shutdown(struct usb_serial *serial)
++static void sierra_disconnect(struct usb_serial *serial)
+ {
+ int i, j;
+ struct usb_serial_port *port;
+@@ -696,10 +696,29 @@ static void sierra_shutdown(struct usb_s
+ for (j = 0; j < N_IN_URB; j++) {
+ usb_kill_urb(portdata->in_urbs[j]);
+ usb_free_urb(portdata->in_urbs[j]);
+- kfree(portdata->in_buffer[j]);
+ }
++ }
++}
++
++static void sierra_release(struct usb_serial *serial)
++{
++ int i, j;
++ struct usb_serial_port *port;
++ struct sierra_port_private *portdata;
++
++ dev_dbg(&serial->dev->dev, "%s\n", __func__);
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ port = serial->port[i];
++ if (!port)
++ continue;
++ portdata = usb_get_serial_port_data(port);
++ if (!portdata)
++ continue;
++
++ for (j = 0; j < N_IN_URB; j++)
++ kfree(portdata->in_buffer[j]);
+ kfree(portdata);
+- usb_set_serial_port_data(port, NULL);
+ }
+ }
+
+@@ -721,7 +740,8 @@ static struct usb_serial_driver sierra_d
+ .tiocmget = sierra_tiocmget,
+ .tiocmset = sierra_tiocmset,
+ .attach = sierra_startup,
+- .shutdown = sierra_shutdown,
++ .disconnect = sierra_disconnect,
++ .release = sierra_release,
+ .read_int_callback = sierra_instat_callback,
+ };
+
+--- a/drivers/usb/serial/spcp8x5.c
++++ b/drivers/usb/serial/spcp8x5.c
+@@ -356,7 +356,7 @@ cleanup:
+ }
+
+ /* call when the device plug out. free all the memory alloced by probe */
+-static void spcp8x5_shutdown(struct usb_serial *serial)
++static void spcp8x5_release(struct usb_serial *serial)
+ {
+ int i;
+ struct spcp8x5_private *priv;
+@@ -366,7 +366,6 @@ static void spcp8x5_shutdown(struct usb_
+ if (priv) {
+ free_ringbuf(priv->buf);
+ kfree(priv);
+- usb_set_serial_port_data(serial->port[i] , NULL);
+ }
+ }
+ }
+@@ -1041,7 +1040,7 @@ static struct usb_serial_driver spcp8x5_
+ .write_bulk_callback = spcp8x5_write_bulk_callback,
+ .chars_in_buffer = spcp8x5_chars_in_buffer,
+ .attach = spcp8x5_startup,
+- .shutdown = spcp8x5_shutdown,
++ .release = spcp8x5_release,
+ };
+
+ static int __init spcp8x5_init(void)
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -148,7 +148,7 @@ struct ti_device {
+ /* Function Declarations */
+
+ static int ti_startup(struct usb_serial *serial);
+-static void ti_shutdown(struct usb_serial *serial);
++static void ti_release(struct usb_serial *serial);
+ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port,
+ struct file *file);
+ static void ti_close(struct tty_struct *tty, struct usb_serial_port *port,
+@@ -271,7 +271,7 @@ static struct usb_serial_driver ti_1port
+ .id_table = ti_id_table_3410,
+ .num_ports = 1,
+ .attach = ti_startup,
+- .shutdown = ti_shutdown,
++ .release = ti_release,
+ .open = ti_open,
+ .close = ti_close,
+ .write = ti_write,
+@@ -299,7 +299,7 @@ static struct usb_serial_driver ti_2port
+ .id_table = ti_id_table_5052,
+ .num_ports = 2,
+ .attach = ti_startup,
+- .shutdown = ti_shutdown,
++ .release = ti_release,
+ .open = ti_open,
+ .close = ti_close,
+ .write = ti_write,
+@@ -506,7 +506,7 @@ free_tdev:
+ }
+
+
+-static void ti_shutdown(struct usb_serial *serial)
++static void ti_release(struct usb_serial *serial)
+ {
+ int i;
+ struct ti_device *tdev = usb_get_serial_data(serial);
+@@ -519,12 +519,10 @@ static void ti_shutdown(struct usb_seria
+ if (tport) {
+ ti_buf_free(tport->tp_write_buf);
+ kfree(tport);
+- usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+
+ kfree(tdev);
+- usb_set_serial_data(serial, NULL);
+ }
+
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -140,6 +140,14 @@ static void destroy_serial(struct kref *
+ if (serial->minor != SERIAL_TTY_NO_MINOR)
+ return_serial(serial);
+
++ serial->type->release(serial);
++
++ for (i = 0; i < serial->num_ports; ++i) {
++ port = serial->port[i];
++ if (port)
++ put_device(&port->dev);
++ }
++
+ /* If this is a "fake" port, we have to clean it up here, as it will
+ * not get cleaned up in port_release() as it was never registered with
+ * the driver core */
+@@ -147,9 +155,8 @@ static void destroy_serial(struct kref *
+ for (i = serial->num_ports;
+ i < serial->num_port_pointers; ++i) {
+ port = serial->port[i];
+- if (!port)
+- continue;
+- port_free(port);
++ if (port)
++ port_free(port);
+ }
+ }
+
+@@ -1061,10 +1068,6 @@ void usb_serial_disconnect(struct usb_in
+ serial->disconnected = 1;
+ mutex_unlock(&serial->disc_mutex);
+
+- /* Unfortunately, many of the sub-drivers expect the port structures
+- * to exist when their shutdown method is called, so we have to go
+- * through this awkward two-step unregistration procedure.
+- */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port) {
+@@ -1075,14 +1078,7 @@ void usb_serial_disconnect(struct usb_in
+ device_del(&port->dev);
+ }
+ }
+- serial->type->shutdown(serial);
+- for (i = 0; i < serial->num_ports; ++i) {
+- port = serial->port[i];
+- if (port) {
+- put_device(&port->dev);
+- serial->port[i] = NULL;
+- }
+- }
++ serial->type->disconnect(serial);
+
+ /* let the last holder of this object
+ * cause it to be cleaned up */
+@@ -1246,7 +1242,8 @@ static void fixup_generic(struct usb_ser
+ set_to_generic_if_null(device, chars_in_buffer);
+ set_to_generic_if_null(device, read_bulk_callback);
+ set_to_generic_if_null(device, write_bulk_callback);
+- set_to_generic_if_null(device, shutdown);
++ set_to_generic_if_null(device, disconnect);
++ set_to_generic_if_null(device, release);
+ set_to_generic_if_null(device, resume);
+ }
+
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -48,7 +48,7 @@ static void visor_unthrottle(struct tty_
+ static int visor_probe(struct usb_serial *serial,
+ const struct usb_device_id *id);
+ static int visor_calc_num_ports(struct usb_serial *serial);
+-static void visor_shutdown(struct usb_serial *serial);
++static void visor_release(struct usb_serial *serial);
+ static void visor_write_bulk_callback(struct urb *urb);
+ static void visor_read_bulk_callback(struct urb *urb);
+ static void visor_read_int_callback(struct urb *urb);
+@@ -203,7 +203,7 @@ static struct usb_serial_driver handspri
+ .attach = treo_attach,
+ .probe = visor_probe,
+ .calc_num_ports = visor_calc_num_ports,
+- .shutdown = visor_shutdown,
++ .release = visor_release,
+ .write = visor_write,
+ .write_room = visor_write_room,
+ .write_bulk_callback = visor_write_bulk_callback,
+@@ -228,7 +228,7 @@ static struct usb_serial_driver clie_5_d
+ .attach = clie_5_attach,
+ .probe = visor_probe,
+ .calc_num_ports = visor_calc_num_ports,
+- .shutdown = visor_shutdown,
++ .release = visor_release,
+ .write = visor_write,
+ .write_room = visor_write_room,
+ .write_bulk_callback = visor_write_bulk_callback,
+@@ -916,7 +916,7 @@ static int clie_5_attach(struct usb_seri
+ return generic_startup(serial);
+ }
+
+-static void visor_shutdown(struct usb_serial *serial)
++static void visor_release(struct usb_serial *serial)
+ {
+ struct visor_private *priv;
+ int i;
+@@ -925,10 +925,7 @@ static void visor_shutdown(struct usb_se
+
+ for (i = 0; i < serial->num_ports; i++) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+- if (priv) {
+- usb_set_serial_port_data(serial->port[i], NULL);
+- kfree(priv);
+- }
++ kfree(priv);
+ }
+ }
+
+--- a/drivers/usb/serial/whiteheat.c
++++ b/drivers/usb/serial/whiteheat.c
+@@ -144,7 +144,7 @@ static int whiteheat_firmware_attach(st
+
+ /* function prototypes for the Connect Tech WhiteHEAT serial converter */
+ static int whiteheat_attach(struct usb_serial *serial);
+-static void whiteheat_shutdown(struct usb_serial *serial);
++static void whiteheat_release(struct usb_serial *serial);
+ static int whiteheat_open(struct tty_struct *tty,
+ struct usb_serial_port *port, struct file *filp);
+ static void whiteheat_close(struct tty_struct *tty,
+@@ -190,7 +190,7 @@ static struct usb_serial_driver whitehea
+ .id_table = id_table_std,
+ .num_ports = 4,
+ .attach = whiteheat_attach,
+- .shutdown = whiteheat_shutdown,
++ .release = whiteheat_release,
+ .open = whiteheat_open,
+ .close = whiteheat_close,
+ .write = whiteheat_write,
+@@ -600,7 +600,7 @@ no_command_buffer:
+ }
+
+
+-static void whiteheat_shutdown(struct usb_serial *serial)
++static void whiteheat_release(struct usb_serial *serial)
+ {
+ struct usb_serial_port *command_port;
+ struct usb_serial_port *port;
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -177,8 +177,10 @@ static inline void usb_set_serial_data(s
+ * This will be called when the struct usb_serial structure is fully set
+ * set up. Do any local initialization of the device, or any private
+ * memory structure allocation at this point in time.
+- * @shutdown: pointer to the driver's shutdown function. This will be
+- * called when the device is removed from the system.
++ * @disconnect: pointer to the driver's disconnect function. This will be
++ * called when the device is unplugged or unbound from the driver.
++ * @release: pointer to the driver's release function. This will be called
++ * when the usb_serial data structure is about to be destroyed.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ * device. This is necessary to allow dynamic ids to be added to
+ * the driver from sysfs.
+@@ -208,7 +210,8 @@ struct usb_serial_driver {
+ int (*attach)(struct usb_serial *serial);
+ int (*calc_num_ports) (struct usb_serial *serial);
+
+- void (*shutdown)(struct usb_serial *serial);
++ void (*disconnect)(struct usb_serial *serial);
++ void (*release)(struct usb_serial *serial);
+
+ int (*port_probe)(struct usb_serial_port *port);
+ int (*port_remove)(struct usb_serial_port *port);
+@@ -288,7 +291,8 @@ extern void usb_serial_generic_read_bulk
+ extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
+ extern void usb_serial_generic_throttle(struct tty_struct *tty);
+ extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
+-extern void usb_serial_generic_shutdown(struct usb_serial *serial);
++extern void usb_serial_generic_disconnect(struct usb_serial *serial);
++extern void usb_serial_generic_release(struct usb_serial *serial);
+ extern int usb_serial_generic_register(int debug);
+ extern void usb_serial_generic_deregister(void);
+
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:11 2009
+Message-Id: <20091206233210.990907937@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:51 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Maciej Sosnowski <maciej.sosnowski@intel.com>,
+ Jeff Kirsher <jeffrey.t.kirsher@intel.com>,
+ "David S. Miller" <davem@davemloft.net>
+Subject: [19/20] dca: redesign locks to fix deadlocks
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=dca-redesign-locks-to-fix-deadlocks.patch
+Content-Length: 4060
+Lines: 165
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Maciej Sosnowski <maciej.sosnowski@intel.com>
+
+commit eb4400e3a040b90a3ad805b01fcbc99a5f615c8f upstream.
+
+Change spin_locks to irqsave to prevent dead-locks.
+Protect adding and deleting to/from dca_providers list.
+Drop the lock during dca_sysfs_add_req() and dca_sysfs_remove_req() calls
+as they might sleep (use GFP_KERNEL allocation).
+
+Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com>
+Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/dca/dca-core.c | 51 +++++++++++++++++++++++++++++++------------------
+ 1 file changed, 33 insertions(+), 18 deletions(-)
+
+--- a/drivers/dca/dca-core.c
++++ b/drivers/dca/dca-core.c
+@@ -28,7 +28,7 @@
+ #include <linux/device.h>
+ #include <linux/dca.h>
+
+-#define DCA_VERSION "1.4"
++#define DCA_VERSION "1.8"
+
+ MODULE_VERSION(DCA_VERSION);
+ MODULE_LICENSE("GPL");
+@@ -60,16 +60,17 @@ int dca_add_requester(struct device *dev
+ {
+ struct dca_provider *dca;
+ int err, slot = -ENODEV;
++ unsigned long flags;
+
+ if (!dev)
+ return -EFAULT;
+
+- spin_lock(&dca_lock);
++ spin_lock_irqsave(&dca_lock, flags);
+
+ /* check if the requester has not been added already */
+ dca = dca_find_provider_by_dev(dev);
+ if (dca) {
+- spin_unlock(&dca_lock);
++ spin_unlock_irqrestore(&dca_lock, flags);
+ return -EEXIST;
+ }
+
+@@ -78,19 +79,21 @@ int dca_add_requester(struct device *dev
+ if (slot >= 0)
+ break;
+ }
+- if (slot < 0) {
+- spin_unlock(&dca_lock);
++
++ spin_unlock_irqrestore(&dca_lock, flags);
++
++ if (slot < 0)
+ return slot;
+- }
+
+ err = dca_sysfs_add_req(dca, dev, slot);
+ if (err) {
+- dca->ops->remove_requester(dca, dev);
+- spin_unlock(&dca_lock);
++ spin_lock_irqsave(&dca_lock, flags);
++ if (dca == dca_find_provider_by_dev(dev))
++ dca->ops->remove_requester(dca, dev);
++ spin_unlock_irqrestore(&dca_lock, flags);
+ return err;
+ }
+
+- spin_unlock(&dca_lock);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(dca_add_requester);
+@@ -103,25 +106,25 @@ int dca_remove_requester(struct device *
+ {
+ struct dca_provider *dca;
+ int slot;
++ unsigned long flags;
+
+ if (!dev)
+ return -EFAULT;
+
+- spin_lock(&dca_lock);
++ spin_lock_irqsave(&dca_lock, flags);
+ dca = dca_find_provider_by_dev(dev);
+ if (!dca) {
+- spin_unlock(&dca_lock);
++ spin_unlock_irqrestore(&dca_lock, flags);
+ return -ENODEV;
+ }
+ slot = dca->ops->remove_requester(dca, dev);
+- if (slot < 0) {
+- spin_unlock(&dca_lock);
++ spin_unlock_irqrestore(&dca_lock, flags);
++
++ if (slot < 0)
+ return slot;
+- }
+
+ dca_sysfs_remove_req(dca, slot);
+
+- spin_unlock(&dca_lock);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(dca_remove_requester);
+@@ -135,17 +138,18 @@ u8 dca_common_get_tag(struct device *dev
+ {
+ struct dca_provider *dca;
+ u8 tag;
++ unsigned long flags;
+
+- spin_lock(&dca_lock);
++ spin_lock_irqsave(&dca_lock, flags);
+
+ dca = dca_find_provider_by_dev(dev);
+ if (!dca) {
+- spin_unlock(&dca_lock);
++ spin_unlock_irqrestore(&dca_lock, flags);
+ return -ENODEV;
+ }
+ tag = dca->ops->get_tag(dca, dev, cpu);
+
+- spin_unlock(&dca_lock);
++ spin_unlock_irqrestore(&dca_lock, flags);
+ return tag;
+ }
+
+@@ -217,11 +221,16 @@ static BLOCKING_NOTIFIER_HEAD(dca_provid
+ int register_dca_provider(struct dca_provider *dca, struct device *dev)
+ {
+ int err;
++ unsigned long flags;
+
+ err = dca_sysfs_add_provider(dca, dev);
+ if (err)
+ return err;
++
++ spin_lock_irqsave(&dca_lock, flags);
+ list_add(&dca->node, &dca_providers);
++ spin_unlock_irqrestore(&dca_lock, flags);
++
+ blocking_notifier_call_chain(&dca_provider_chain,
+ DCA_PROVIDER_ADD, NULL);
+ return 0;
+@@ -234,9 +243,15 @@ EXPORT_SYMBOL_GPL(register_dca_provider)
+ */
+ void unregister_dca_provider(struct dca_provider *dca)
+ {
++ unsigned long flags;
++
+ blocking_notifier_call_chain(&dca_provider_chain,
+ DCA_PROVIDER_REMOVE, NULL);
++
++ spin_lock_irqsave(&dca_lock, flags);
+ list_del(&dca->node);
++ spin_unlock_irqrestore(&dca_lock, flags);
++
+ dca_sysfs_remove_provider(dca);
+ }
+ EXPORT_SYMBOL_GPL(unregister_dca_provider);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:11 2009
+Message-Id: <20091206233211.121828427@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:52 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk,
+ Willy Tarreau <w@1wt.eu>,
+ Jean Delvare <khali@linux-fr.org>
+Subject: [20/20] hwmon: (it87) Fix VID reading on IT8718F
+References: <20091206233032.387950574@mini.kroah.org>
+Content-Disposition: inline; filename=hwmon-it87-fix-vid-reading-on-it8718f.patch
+Content-Length: 752
+Lines: 28
+
+2.6.27-stable review patch. If anyone has any objections, please let us know.
+
+------------------
+From: Jean Delvare <khali@linux-fr.org>
+
+commit 371dc4a6d8c3c74a9a1c74b87c2affb3fcef6500 upstream
+
+Comparing apples to bananas doesn't seem right.
+
+The bug has been there since support for the IT8718F was added, so
+VID never worked for this chip.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/it87.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/hwmon/it87.c
++++ b/drivers/hwmon/it87.c
+@@ -1017,7 +1017,7 @@ static int __init it87_find(unsigned sho
+ int reg;
+
+ superio_select(GPIO);
+- if (chip_type == it8718)
++ if (sio_data->type == it8718)
+ sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
+
+ reg = superio_inb(IT87_SIO_PINX2_REG);
+
+
+From gregkh@mini.kroah.org Sun Dec 6 15:32:08 2009
+Message-Id: <20091206233032.387950574@mini.kroah.org>
+User-Agent: quilt/0.48-1
+Date: Sun, 06 Dec 2009 15:30:32 -0800
+From: Greg KH <gregkh@suse.de>
+To: linux-kernel@vger.kernel.org,
+ stable@kernel.org
+Cc: stable-review@kernel.org,
+ torvalds@linux-foundation.org,
+ akpm@linux-foundation.org,
+ alan@lxorguk.ukuu.org.uk
+Subject: [00/20] 2.6.27.40-stable review
+Content-Length: 3708
+Lines: 73
+
+
+This is the start of the stable review cycle for the 2.6.27.40 release.
+There are 20 patches in this series, all will be posted as a response to
+this one. If anyone has any issues with these being applied, please let
+us know. If anyone is a maintainer of the proper subsystem, and wants
+to add a Signed-off-by: line to the patch, please respond with it.
+
+Responses should be made by Tuesday Dec 8, 20:00:00 UTC. Anything
+received after that time might be too late.
+
+The whole patch series can be found in one patch at:
+ kernel.org/pub/linux/kernel/v2.6/stable-review/patch-2.6.27.40-rc1.gz
+and the diffstat can be found below.
+
+thanks,
+
+greg k-h
+
+ Makefile | 2 +-
+ arch/x86/kernel/acpi/processor.c | 3 +-
+ drivers/dca/dca-core.c | 51 ++++++++++-----
+ drivers/hwmon/it87.c | 2 +-
+ drivers/isdn/hisax/hfc_usb.c | 4 +-
+ drivers/media/common/tuners/tda18271-fe.c | 8 +-
+ drivers/media/dvb/frontends/dib7000p.c | 5 ++
+ drivers/media/video/em28xx/em28xx-audio.c | 5 ++
+ drivers/media/video/s2255drv.c | 5 --
+ drivers/misc/thinkpad_acpi.c | 2 +-
+ drivers/scsi/gdth.c | 2 +-
+ drivers/usb/host/ohci-hcd.c | 5 ++
+ drivers/usb/host/ohci-pci.c | 20 ++++++
+ drivers/usb/host/ohci-q.c | 18 ++++--
+ drivers/usb/host/ohci.h | 9 +++
+ drivers/usb/serial/aircable.c | 5 +-
+ drivers/usb/serial/belkin_sa.c | 7 +-
+ drivers/usb/serial/cp2101.c | 6 +-
+ drivers/usb/serial/cyberjack.c | 20 +++++--
+ drivers/usb/serial/cypress_m8.c | 11 ++--
+ drivers/usb/serial/digi_acceleport.c | 20 +++++--
+ drivers/usb/serial/empeg.c | 8 ---
+ drivers/usb/serial/ftdi_sio.c | 14 ----
+ drivers/usb/serial/garmin_gps.c | 16 ++++-
+ drivers/usb/serial/generic.c | 9 ++-
+ drivers/usb/serial/io_edgeport.c | 29 ++++++---
+ drivers/usb/serial/io_tables.h | 12 +++-
+ drivers/usb/serial/io_ti.c | 22 +++++--
+ drivers/usb/serial/ipaq.c | 7 --
+ drivers/usb/serial/iuu_phoenix.c | 6 +-
+ drivers/usb/serial/keyspan.c | 13 ++++-
+ drivers/usb/serial/keyspan.h | 12 +++-
+ drivers/usb/serial/keyspan_pda.c | 4 +-
+ drivers/usb/serial/kl5kusb105.c | 39 +++++++-----
+ drivers/usb/serial/kobil_sct.c | 12 +---
+ drivers/usb/serial/mct_u232.c | 13 ++---
+ drivers/usb/serial/mos7720.c | 9 +--
+ drivers/usb/serial/mos7840.c | 48 ++++++++++++---
+ drivers/usb/serial/omninet.c | 19 +++++-
+ drivers/usb/serial/option.c | 97 ++++++++++++++++++++++++++---
+ drivers/usb/serial/oti6858.c | 7 +-
+ drivers/usb/serial/pl2303.c | 5 +-
+ drivers/usb/serial/sierra.c | 28 +++++++-
+ drivers/usb/serial/spcp8x5.c | 5 +-
+ drivers/usb/serial/ti_usb_3410_5052.c | 10 +--
+ drivers/usb/serial/usb-serial.c | 29 ++++-----
+ drivers/usb/serial/visor.c | 13 ++---
+ drivers/usb/serial/whiteheat.c | 6 +-
+ fs/fuse/dir.c | 3 +
+ fs/fuse/file.c | 3 +-
+ fs/jffs2/read.c | 9 ++-
+ include/linux/usb/serial.h | 12 +++-
+ sound/arm/aaci.c | 6 ++-
+ sound/usb/usbaudio.h | 2 +-
+ 54 files changed, 493 insertions(+), 244 deletions(-)
+