]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
.30 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Tue, 30 Jun 2009 17:50:44 +0000 (10:50 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 30 Jun 2009 17:50:44 +0000 (10:50 -0700)
13 files changed:
queue-2.6.30/ath5k-avoid-pci-fatal-interrupts-by-restoring-retry_timeout-disabling.patch [new file with mode: 0644]
queue-2.6.30/mm-fix-handling-of-pagesets-for-downed-cpus.patch [new file with mode: 0644]
queue-2.6.30/mv643xx_eth-fix-unicast-filter-programming-in-promiscuous-mode.patch [new file with mode: 0644]
queue-2.6.30/n_r3964-fix-lock-imbalance.patch [new file with mode: 0644]
queue-2.6.30/parport_pc-after-superio-probing-restore-original-register-values.patch [new file with mode: 0644]
queue-2.6.30/parport_pc-set-properly-the-dma_mask-for-parport_pc-device.patch [new file with mode: 0644]
queue-2.6.30/pci-pm-fix-handling-of-devices-without-pm-support-by-pci_target_state.patch [new file with mode: 0644]
queue-2.6.30/pci-pm-follow-pci_pm_ctrl_no_soft_reset-during-transitions-from-d3.patch [new file with mode: 0644]
queue-2.6.30/pcmcia-cm4000-fix-lock-imbalance.patch [new file with mode: 0644]
queue-2.6.30/qla2xxx-correct-overflow-during-dump-processing-on-large-memory-isp23xx-parts.patch [new file with mode: 0644]
queue-2.6.30/series
queue-2.6.30/sound-seq_midi_event-fix-decoding-of-rpn-events.patch [new file with mode: 0644]
queue-2.6.30/usb-serial-replace-shutdown-with-disconnect-release.patch [new file with mode: 0644]

diff --git a/queue-2.6.30/ath5k-avoid-pci-fatal-interrupts-by-restoring-retry_timeout-disabling.patch b/queue-2.6.30/ath5k-avoid-pci-fatal-interrupts-by-restoring-retry_timeout-disabling.patch
new file mode 100644 (file)
index 0000000..ab9b4bf
--- /dev/null
@@ -0,0 +1,37 @@
+From 8451d22dad40a66416b8d9c0952efa09ec5398c5 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni.malinen@atheros.com>
+Date: Tue, 16 Jun 2009 11:59:23 +0300
+Subject: ath5k: avoid PCI FATAL interrupts by restoring RETRY_TIMEOUT disabling
+
+From: Jouni Malinen <jouni.malinen@atheros.com>
+
+commit 8451d22dad40a66416b8d9c0952efa09ec5398c5 upstream.
+
+This reverts 'ath5k: remove dummy PCI "retry timeout" fix' on the
+same theory as in 'ath9k: Fix PCI FATAL interrupts by restoring
+RETRY_TIMEOUT disabling'.
+
+Reported-by: Bob Copeland <me@bobcopeland.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/ath5k/base.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/wireless/ath5k/base.c
++++ b/drivers/net/wireless/ath5k/base.c
+@@ -685,6 +685,13 @@ ath5k_pci_resume(struct pci_dev *pdev)
+       if (err)
+               return err;
++      /*
++       * Suspend/Resume resets the PCI configuration space, so we have to
++       * re-disable the RETRY_TIMEOUT register (0x41) to keep
++       * PCI Tx retries from interfering with C3 CPU state
++       */
++      pci_write_config_byte(pdev, 0x41, 0);
++
+       err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+       if (err) {
+               ATH5K_ERR(sc, "request_irq failed\n");
diff --git a/queue-2.6.30/mm-fix-handling-of-pagesets-for-downed-cpus.patch b/queue-2.6.30/mm-fix-handling-of-pagesets-for-downed-cpus.patch
new file mode 100644 (file)
index 0000000..47e55f5
--- /dev/null
@@ -0,0 +1,62 @@
+From 364df0ebfbbb1330bfc6ca159f4d6020efc15a12 Mon Sep 17 00:00:00 2001
+From: Dimitri Sivanich <sivanich@sgi.com>
+Date: Tue, 23 Jun 2009 12:37:04 -0700
+Subject: mm: fix handling of pagesets for downed cpus
+
+From: Dimitri Sivanich <sivanich@sgi.com>
+
+commit 364df0ebfbbb1330bfc6ca159f4d6020efc15a12 upstream.
+
+After downing/upping a cpu, an attempt to set
+/proc/sys/vm/percpu_pagelist_fraction results in an oops in
+percpu_pagelist_fraction_sysctl_handler().
+
+If a processor is downed then we need to set the pageset pointer back to
+the boot pageset.
+
+Updates of the high water marks should not access pagesets of unpopulated
+zones (those pointer go to the boot pagesets which would be no longer
+functional if their size would be increased beyond zero).
+
+Signed-off-by: Dimitri Sivanich <sivanich@sgi.com>
+Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
+Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Nick Piggin <nickpiggin@yahoo.com.au>
+Cc: Mel Gorman <mel@csn.ul.ie>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/page_alloc.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -2812,7 +2812,7 @@ bad:
+               if (dzone == zone)
+                       break;
+               kfree(zone_pcp(dzone, cpu));
+-              zone_pcp(dzone, cpu) = NULL;
++              zone_pcp(dzone, cpu) = &boot_pageset[cpu];
+       }
+       return -ENOMEM;
+ }
+@@ -2827,7 +2827,7 @@ static inline void free_zone_pagesets(in
+               /* Free per_cpu_pageset if it is slab allocated */
+               if (pset != &boot_pageset[cpu])
+                       kfree(pset);
+-              zone_pcp(zone, cpu) = NULL;
++              zone_pcp(zone, cpu) = &boot_pageset[cpu];
+       }
+ }
+@@ -4501,7 +4501,7 @@ int percpu_pagelist_fraction_sysctl_hand
+       ret = proc_dointvec_minmax(table, write, file, buffer, length, ppos);
+       if (!write || (ret == -EINVAL))
+               return ret;
+-      for_each_zone(zone) {
++      for_each_populated_zone(zone) {
+               for_each_online_cpu(cpu) {
+                       unsigned long  high;
+                       high = zone->present_pages / percpu_pagelist_fraction;
diff --git a/queue-2.6.30/mv643xx_eth-fix-unicast-filter-programming-in-promiscuous-mode.patch b/queue-2.6.30/mv643xx_eth-fix-unicast-filter-programming-in-promiscuous-mode.patch
new file mode 100644 (file)
index 0000000..a6a687b
--- /dev/null
@@ -0,0 +1,60 @@
+From 6877f54e6a3326c99aaf84b7bff6a3019da0b847 Mon Sep 17 00:00:00 2001
+From: Prabhanjan Sarnaik <sarnaik@marvell.com>
+Date: Thu, 18 Jun 2009 11:35:02 +0000
+Subject: mv643xx_eth: fix unicast filter programming in promiscuous mode
+
+From: Prabhanjan Sarnaik <sarnaik@marvell.com>
+
+commit 6877f54e6a3326c99aaf84b7bff6a3019da0b847 upstream.
+
+The Unicast Promiscious Mode (UPM) bit in the mv643xx_eth port
+configuration register doesn't do exactly what its name would suggest:
+setting this bit merely enables reception of all unicast frames with a
+destination address that differs from our local MAC address in bits
+[47:4].  In particular, it doesn't have any effect on unicast frames
+with a destination address that matches our MAC address in bits [47:4]
+-- these will still be tested against the 16-entry unicast address
+filter table.
+
+Therefore, if the interface is set to promiscuous mode, just setting
+the unicast promiscuous bit isn't enough -- we need to set all filter
+bits in the unicast filter table to 1 as well.
+
+Reported-by: Sachin Sanap <ssanap@marvell.com>
+Signed-off-by: Prabhanjan Sarnaik <sarnaik@marvell.com>
+Tested-by: Siddarth Gore <gores@marvell.com>
+Tested-by: Mahavir Jain <mjain@marvell.com>
+Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/mv643xx_eth.c |    7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/mv643xx_eth.c
++++ b/drivers/net/mv643xx_eth.c
+@@ -1751,12 +1751,12 @@ static void mv643xx_eth_program_unicast_
+       uc_addr_set(mp, dev->dev_addr);
+-      port_config = rdlp(mp, PORT_CONFIG);
++      port_config = rdlp(mp, PORT_CONFIG) & ~UNICAST_PROMISCUOUS_MODE;
++
+       nibbles = uc_addr_filter_mask(dev);
+       if (!nibbles) {
+               port_config |= UNICAST_PROMISCUOUS_MODE;
+-              wrlp(mp, PORT_CONFIG, port_config);
+-              return;
++              nibbles = 0xffff;
+       }
+       for (i = 0; i < 16; i += 4) {
+@@ -1777,7 +1777,6 @@ static void mv643xx_eth_program_unicast_
+               wrl(mp, off, v);
+       }
+-      port_config &= ~UNICAST_PROMISCUOUS_MODE;
+       wrlp(mp, PORT_CONFIG, port_config);
+ }
diff --git a/queue-2.6.30/n_r3964-fix-lock-imbalance.patch b/queue-2.6.30/n_r3964-fix-lock-imbalance.patch
new file mode 100644 (file)
index 0000000..75e833f
--- /dev/null
@@ -0,0 +1,85 @@
+From eca41044268887838fa122aa24475df8f23d614c Mon Sep 17 00:00:00 2001
+From: Jiri Slaby <jirislaby@gmail.com>
+Date: Mon, 22 Jun 2009 18:42:03 +0100
+Subject: n_r3964: fix lock imbalance
+
+From: Jiri Slaby <jirislaby@gmail.com>
+
+commit eca41044268887838fa122aa24475df8f23d614c upstream.
+
+There is omitted BKunL in r3964_read.
+
+Centralize the paths to one point with one unlock.
+
+Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/n_r3964.c |   26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+--- a/drivers/char/n_r3964.c
++++ b/drivers/char/n_r3964.c
+@@ -1062,7 +1062,7 @@ static ssize_t r3964_read(struct tty_str
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg;
+       struct r3964_client_message theMsg;
+-      int count;
++      int ret;
+       TRACE_L("read()");
+@@ -1074,8 +1074,8 @@ static ssize_t r3964_read(struct tty_str
+               if (pMsg == NULL) {
+                       /* no messages available. */
+                       if (file->f_flags & O_NONBLOCK) {
+-                              unlock_kernel();
+-                              return -EAGAIN;
++                              ret = -EAGAIN;
++                              goto unlock;
+                       }
+                       /* block until there is a message: */
+                       wait_event_interruptible(pInfo->read_wait,
+@@ -1085,29 +1085,31 @@ static ssize_t r3964_read(struct tty_str
+               /* If we still haven't got a message, we must have been signalled */
+               if (!pMsg) {
+-                      unlock_kernel();
+-                      return -EINTR;
++                      ret = -EINTR;
++                      goto unlock;
+               }
+               /* deliver msg to client process: */
+               theMsg.msg_id = pMsg->msg_id;
+               theMsg.arg = pMsg->arg;
+               theMsg.error_code = pMsg->error_code;
+-              count = sizeof(struct r3964_client_message);
++              ret = sizeof(struct r3964_client_message);
+               kfree(pMsg);
+               TRACE_M("r3964_read - msg kfree %p", pMsg);
+-              if (copy_to_user(buf, &theMsg, count)) {
+-                      unlock_kernel();
+-                      return -EFAULT;
++              if (copy_to_user(buf, &theMsg, ret)) {
++                      ret = -EFAULT;
++                      goto unlock;
+               }
+-              TRACE_PS("read - return %d", count);
+-              return count;
++              TRACE_PS("read - return %d", ret);
++              goto unlock;
+       }
++      ret = -EPERM;
++unlock:
+       unlock_kernel();
+-      return -EPERM;
++      return ret;
+ }
+ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
diff --git a/queue-2.6.30/parport_pc-after-superio-probing-restore-original-register-values.patch b/queue-2.6.30/parport_pc-after-superio-probing-restore-original-register-values.patch
new file mode 100644 (file)
index 0000000..1be032a
--- /dev/null
@@ -0,0 +1,134 @@
+From e2434dc1c19412639dd047a4d4eff8ed0e5d0d50 Mon Sep 17 00:00:00 2001
+From: Jens Rottmann <JRottmann@LiPPERTEmbedded.de>
+Date: Mon, 22 Jun 2009 16:51:49 +0100
+Subject: parport_pc: after superio probing restore original register values
+
+From: Jens Rottmann <JRottmann@LiPPERTEmbedded.de>
+
+commit e2434dc1c19412639dd047a4d4eff8ed0e5d0d50 upstream.
+
+CONFIG_PARPORT_PC_SUPERIO probes for various superio chips by writing
+byte sequences to a set of different potential I/O ranges.  But the
+probed ranges are not exclusive to parallel ports.  Some of our boards
+just happen to have a watchdog in one of them.  Took us almost a week
+to figure out why some distros reboot without warning after running
+flawlessly for 3 hours.  For exactly 170 = 0xAA minutes, that is ...
+
+Fixed by restoring original values after probing.  Also fixed too small
+request_region() in detect_and_report_it87().
+
+Signed-off-by: Jens Rottmann <JRottmann@LiPPERTEmbedded.de>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Acked-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/parport/parport_pc.c |   31 +++++++++++++++++++++++++------
+ 1 file changed, 25 insertions(+), 6 deletions(-)
+
+--- a/drivers/parport/parport_pc.c
++++ b/drivers/parport/parport_pc.c
+@@ -1413,11 +1413,13 @@ static void __devinit decode_smsc(int ef
+ static void __devinit winbond_check(int io, int key)
+ {
+-      int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
++      int origval, devid, devrev, oldid, x_devid, x_devrev, x_oldid;
+       if (!request_region(io, 3, __func__))
+               return;
++      origval = inb(io); /* Save original value */
++
+       /* First probe without key */
+       outb(0x20,io);
+       x_devid=inb(io+1);
+@@ -1437,6 +1439,8 @@ static void __devinit winbond_check(int 
+       oldid=inb(io+1);
+       outb(0xaa,io);    /* Magic Seal */
++      outb(origval, io); /* in case we poked some entirely different hardware */
++
+       if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
+               goto out; /* protection against false positives */
+@@ -1447,11 +1451,15 @@ out:
+ static void __devinit winbond_check2(int io,int key)
+ {
+-        int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
++      int origval[3], devid, devrev, oldid, x_devid, x_devrev, x_oldid;
+       if (!request_region(io, 3, __func__))
+               return;
++      origval[0] = inb(io); /* Save original values */
++      origval[1] = inb(io + 1);
++      origval[2] = inb(io + 2);
++
+       /* First probe without the key */
+       outb(0x20,io+2);
+       x_devid=inb(io+2);
+@@ -1470,6 +1478,10 @@ static void __devinit winbond_check2(int
+         oldid=inb(io+2);
+         outb(0xaa,io);    /* Magic Seal */
++      outb(origval[0], io); /* in case we poked some entirely different hardware */
++      outb(origval[1], io + 1);
++      outb(origval[2], io + 2);
++
+       if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid))
+               goto out; /* protection against false positives */
+@@ -1480,11 +1492,13 @@ out:
+ static void __devinit smsc_check(int io, int key)
+ {
+-        int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;
++      int origval, id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev;
+       if (!request_region(io, 3, __func__))
+               return;
++      origval = inb(io); /* Save original value */
++
+       /* First probe without the key */
+       outb(0x0d,io);
+       x_oldid=inb(io+1);
+@@ -1508,6 +1522,8 @@ static void __devinit smsc_check(int io,
+       rev=inb(io+1);
+         outb(0xaa,io);    /* Magic Seal */
++      outb(origval, io); /* in case we poked some entirely different hardware */
++
+       if ((x_id == id) && (x_oldrev == oldrev) &&
+           (x_oldid == oldid) && (x_rev == rev))
+               goto out; /* protection against false positives */
+@@ -1544,11 +1560,12 @@ static void __devinit detect_and_report_
+ static void __devinit detect_and_report_it87(void)
+ {
+       u16 dev;
+-      u8 r;
++      u8 origval, r;
+       if (verbose_probing)
+               printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
+-      if (!request_region(0x2e, 1, __func__))
++      if (!request_region(0x2e, 2, __func__))
+               return;
++      origval = inb(0x2e);            /* Save original value */
+       outb(0x87, 0x2e);
+       outb(0x01, 0x2e);
+       outb(0x55, 0x2e);
+@@ -1568,8 +1585,10 @@ static void __devinit detect_and_report_
+               outb(r | 8, 0x2F);
+               outb(0x02, 0x2E);       /* Lock */
+               outb(0x02, 0x2F);
++      } else {
++              outb(origval, 0x2e);    /* Oops, sorry to disturb */
+       }
+-      release_region(0x2e, 1);
++      release_region(0x2e, 2);
+ }
+ #endif /* CONFIG_PARPORT_PC_SUPERIO */
diff --git a/queue-2.6.30/parport_pc-set-properly-the-dma_mask-for-parport_pc-device.patch b/queue-2.6.30/parport_pc-set-properly-the-dma_mask-for-parport_pc-device.patch
new file mode 100644 (file)
index 0000000..4a02455
--- /dev/null
@@ -0,0 +1,48 @@
+From dfa7c4d869b7d3d37b70f1de856f2901b6ebfcf0 Mon Sep 17 00:00:00 2001
+From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
+Date: Mon, 22 Jun 2009 16:54:27 +0100
+Subject: parport_pc: set properly the dma_mask for parport_pc device
+
+From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
+
+commit dfa7c4d869b7d3d37b70f1de856f2901b6ebfcf0 upstream.
+
+parport_pc_probe_port() creates the own 'parport_pc' device if the
+device argument is NULL. Then parport_pc_probe_port() doesn't
+initialize the dma_mask and coherent_dma_mask of the device and calls
+dma_alloc_coherent with it. dma_alloc_coherent fails because
+dma_alloc_coherent() doesn't accept the uninitialized dma_mask:
+
+http://lkml.org/lkml/2009/6/16/150
+
+Long ago, X86_32 and X86_64 had the own dma_alloc_coherent
+implementations; X86_32 accepted a device having dma_mask that is not
+initialized however X86_64 didn't. When we merged them, we chose to
+prohibit a device having dma_mask that is not initialized. I think
+that it's good to require drivers to set up dma_mask (and
+coherent_dma_mask) properly if the drivers want DMA.
+
+Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
+Reported-by: Malcom Blaney <malcolm.blaney@maptek.com.au>
+Tested-by: Malcom Blaney <malcolm.blaney@maptek.com.au>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Acked-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/parport/parport_pc.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/parport/parport_pc.c
++++ b/drivers/parport/parport_pc.c
+@@ -2193,6 +2193,9 @@ struct parport *parport_pc_probe_port(un
+               if (IS_ERR(pdev))
+                       return NULL;
+               dev = &pdev->dev;
++
++              dev->coherent_dma_mask = DMA_BIT_MASK(24);
++              dev->dma_mask = &dev->coherent_dma_mask;
+       }
+       ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
diff --git a/queue-2.6.30/pci-pm-fix-handling-of-devices-without-pm-support-by-pci_target_state.patch b/queue-2.6.30/pci-pm-fix-handling-of-devices-without-pm-support-by-pci_target_state.patch
new file mode 100644 (file)
index 0000000..dcc94f2
--- /dev/null
@@ -0,0 +1,48 @@
+From d2abdf62882d982c58e7a6b09ecdcfcc28075e2e Mon Sep 17 00:00:00 2001
+From: Rafael J. Wysocki <rjw@sisk.pl>
+Date: Sun, 14 Jun 2009 21:25:02 +0200
+Subject: PCI PM: Fix handling of devices without PM support by pci_target_state()
+
+From: Rafael J. Wysocki <rjw@sisk.pl>
+
+commit d2abdf62882d982c58e7a6b09ecdcfcc28075e2e upstream.
+
+If a PCI device is not power-manageable either by the platform, or
+with the help of the native PCI PM interface, pci_target_state() will
+return either PCI_D3hot, or PCI_POWER_ERROR for it, depending on
+whether or not the device is configured to wake up the system.  Alas,
+none of these return values is correct, because each of them causes
+pci_prepare_to_sleep() to return error code, although it should
+complete successfully in such a case.
+
+Fix this problem by making pci_target_state() always return PCI_D0
+for devices that cannot be power managed.
+
+Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/pci.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -1282,15 +1282,14 @@ pci_power_t pci_target_state(struct pci_
+               default:
+                       target_state = state;
+               }
++      } else if (!dev->pm_cap) {
++              target_state = PCI_D0;
+       } else if (device_may_wakeup(&dev->dev)) {
+               /*
+                * Find the deepest state from which the device can generate
+                * wake-up events, make it the target state and enable device
+                * to generate PME#.
+                */
+-              if (!dev->pm_cap)
+-                      return PCI_POWER_ERROR;
+-
+               if (dev->pme_support) {
+                       while (target_state
+                             && !(dev->pme_support & (1 << target_state)))
diff --git a/queue-2.6.30/pci-pm-follow-pci_pm_ctrl_no_soft_reset-during-transitions-from-d3.patch b/queue-2.6.30/pci-pm-follow-pci_pm_ctrl_no_soft_reset-during-transitions-from-d3.patch
new file mode 100644 (file)
index 0000000..d15519c
--- /dev/null
@@ -0,0 +1,42 @@
+From f62795f1e892ca9269849fa83de97621da7e02c0 Mon Sep 17 00:00:00 2001
+From: Rafael J. Wysocki <rjw@sisk.pl>
+Date: Mon, 18 May 2009 22:51:12 +0200
+Subject: PCI PM: Follow PCI_PM_CTRL_NO_SOFT_RESET during transitions from D3
+
+From: Rafael J. Wysocki <rjw@sisk.pl>
+
+commit f62795f1e892ca9269849fa83de97621da7e02c0 upstream.
+
+According to the PCI PM specification (PCI Bus Power Management
+Interface Specification, Rev. 1.2, Section 5.4.1) we are supposed to
+reinitialize devices that have PCI_PM_CTRL_NO_SOFT_RESET clear during
+all transitions from PCI_D3hot to PCI_D0, but we only do it if the
+device's current_state field is equal to PCI_UNKNOWN.
+
+This may lead to problems if a device with PCI_PM_CTRL_NO_SOFT_RESET
+unset is put into PCI_D3hot at run time by its driver and
+pci_set_power_state() is used to put it back into PCI_D0, because in
+that case the device will remain uninitialized after
+pci_set_power_state() has returned.  Prevent that from happening by
+modifying pci_raw_set_power_state() to reinitialize devices with
+PCI_PM_CTRL_NO_SOFT_RESET unset during all transitions from D3 to D0.
+
+Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
+Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/pci.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -480,6 +480,8 @@ static int pci_raw_set_power_state(struc
+               pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+               pmcsr |= state;
+               break;
++      case PCI_D3hot:
++      case PCI_D3cold:
+       case PCI_UNKNOWN: /* Boot-up */
+               if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot
+                && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET))
diff --git a/queue-2.6.30/pcmcia-cm4000-fix-lock-imbalance.patch b/queue-2.6.30/pcmcia-cm4000-fix-lock-imbalance.patch
new file mode 100644 (file)
index 0000000..138209c
--- /dev/null
@@ -0,0 +1,32 @@
+From 69ae59d7d8df14413cf0a97b3e372d7dc8352563 Mon Sep 17 00:00:00 2001
+From: Jiri Slaby <jirislaby@gmail.com>
+Date: Mon, 22 Jun 2009 18:42:10 +0100
+Subject: pcmcia/cm4000: fix lock imbalance
+
+From: Jiri Slaby <jirislaby@gmail.com>
+
+commit 69ae59d7d8df14413cf0a97b3e372d7dc8352563 upstream.
+
+Don't return from switch/case, break instead, so that we unlock BKL.
+
+Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/pcmcia/cm4000_cs.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/pcmcia/cm4000_cs.c
++++ b/drivers/char/pcmcia/cm4000_cs.c
+@@ -1575,7 +1575,8 @@ static long cmm_ioctl(struct file *filp,
+               clear_bit(LOCK_IO, &dev->flags);
+               wake_up_interruptible(&dev->ioq);
+-              return 0;
++              rc = 0;
++              break;
+       case CM_IOCSPTS:
+               {
+                       struct ptsreq krnptsreq;
diff --git a/queue-2.6.30/qla2xxx-correct-overflow-during-dump-processing-on-large-memory-isp23xx-parts.patch b/queue-2.6.30/qla2xxx-correct-overflow-during-dump-processing-on-large-memory-isp23xx-parts.patch
new file mode 100644 (file)
index 0000000..49fbf39
--- /dev/null
@@ -0,0 +1,33 @@
+From e18e963b7e533149676b5d387d0a56160df9f111 Mon Sep 17 00:00:00 2001
+From: Andrew Vasquez <andrew.vasquez@qlogic.com>
+Date: Wed, 17 Jun 2009 10:30:31 -0700
+Subject: qla2xxx: Correct (again) overflow during dump-processing on large-memory ISP23xx parts.
+
+From: Andrew Vasquez <andrew.vasquez@qlogic.com>
+
+commit e18e963b7e533149676b5d387d0a56160df9f111 upstream.
+
+Commit 7b867cf76fbcc8d77867cbec6f509f71dce8a98f ([SCSI] qla2xxx:
+Refactor qla data structures) inadvertently reverted
+e792121ec85672c1fa48f79d13986a3f4f56c590 ([SCSI] qla2xxx: Correct
+overflow during dump-processing on large-memory ISP23xx parts.).
+
+Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
+Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/scsi/qla2xxx/qla_dbg.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/qla2xxx/qla_dbg.c
++++ b/drivers/scsi/qla2xxx/qla_dbg.c
+@@ -218,7 +218,7 @@ qla24xx_soft_reset(struct qla_hw_data *h
+ static int
+ qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram,
+-    uint16_t ram_words, void **nxt)
++    uint32_t ram_words, void **nxt)
+ {
+       int rval;
+       uint32_t cnt, stat, timer, words, idx;
index 308760c1bc6a7626a4f9ab14fc22c71adf39ce4b..a6f9034527ee698cc848658aab932ba4bef89962 100644 (file)
@@ -79,3 +79,15 @@ cifs-fix-fh_mutex-locking-in-cifs_reopen_file.patch
 vt_ioctl-fix-lock-imbalance.patch
 x86-fix-non-lazy-gs-handling-in-sys_vm86.patch
 x86-set-cpu_llc_id-on-amd-cpus.patch
+usb-serial-replace-shutdown-with-disconnect-release.patch
+pcmcia-cm4000-fix-lock-imbalance.patch
+n_r3964-fix-lock-imbalance.patch
+parport_pc-set-properly-the-dma_mask-for-parport_pc-device.patch
+parport_pc-after-superio-probing-restore-original-register-values.patch
+mv643xx_eth-fix-unicast-filter-programming-in-promiscuous-mode.patch
+ath5k-avoid-pci-fatal-interrupts-by-restoring-retry_timeout-disabling.patch
+sound-seq_midi_event-fix-decoding-of-rpn-events.patch
+pci-pm-fix-handling-of-devices-without-pm-support-by-pci_target_state.patch
+pci-pm-follow-pci_pm_ctrl_no_soft_reset-during-transitions-from-d3.patch
+qla2xxx-correct-overflow-during-dump-processing-on-large-memory-isp23xx-parts.patch
+mm-fix-handling-of-pagesets-for-downed-cpus.patch
diff --git a/queue-2.6.30/sound-seq_midi_event-fix-decoding-of-rpn-events.patch b/queue-2.6.30/sound-seq_midi_event-fix-decoding-of-rpn-events.patch
new file mode 100644 (file)
index 0000000..ea8caec
--- /dev/null
@@ -0,0 +1,38 @@
+From 6423f9ea8035138d70bae1a278d3b57b743f8b3e Mon Sep 17 00:00:00 2001
+From: Clemens Ladisch <clemens@ladisch.de>
+Date: Mon, 22 Jun 2009 10:01:59 +0200
+Subject: sound: seq_midi_event: fix decoding of (N)RPN events
+
+From: Clemens Ladisch <clemens@ladisch.de>
+
+commit 6423f9ea8035138d70bae1a278d3b57b743f8b3e upstream.
+
+When decoding (N)RPN sequencer events into raw MIDI commands, the
+extra_decode_xrpn() function had accidentally swapped the MSB and LSB
+controller values of both the parameter number and the data value.
+
+Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/core/seq/seq_midi_event.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/sound/core/seq/seq_midi_event.c
++++ b/sound/core/seq/seq_midi_event.c
+@@ -504,10 +504,10 @@ static int extra_decode_xrpn(struct snd_
+       if (dev->nostat && count < 12)
+               return -ENOMEM;
+       cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
+-      bytes[0] = ev->data.control.param & 0x007f;
+-      bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
+-      bytes[2] = ev->data.control.value & 0x007f;
+-      bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
++      bytes[0] = (ev->data.control.param & 0x3f80) >> 7;
++      bytes[1] = ev->data.control.param & 0x007f;
++      bytes[2] = (ev->data.control.value & 0x3f80) >> 7;
++      bytes[3] = ev->data.control.value & 0x007f;
+       if (cmd != dev->lastcmd && !dev->nostat) {
+               if (count < 9)
+                       return -ENOMEM;
diff --git a/queue-2.6.30/usb-serial-replace-shutdown-with-disconnect-release.patch b/queue-2.6.30/usb-serial-replace-shutdown-with-disconnect-release.patch
new file mode 100644 (file)
index 0000000..59b3a5c
--- /dev/null
@@ -0,0 +1,1604 @@
+From stern@rowland.harvard.edu  Tue Jun 30 09:54:21 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 30 Jun 2009 11:26:47 -0400 (EDT)
+Subject: usb-serial: replace shutdown with disconnect, release
+To: stable@kernel.org
+Message-ID: <Pine.LNX.4.44L0.0906301125070.3049-100000@iolanthe.rowland.org>
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit f9c99bb8b3a1ec81af68d484a551307326c2e933 upstream
+
+This patch 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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/uc2322/aten2011.c     |    4 +--
+ drivers/usb/serial/aircable.c         |    5 +---
+ drivers/usb/serial/belkin_sa.c        |    7 ++---
+ drivers/usb/serial/cp210x.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          |   42 +++++++++++++++++++++++++++++-----
+ drivers/usb/serial/omninet.c          |   19 ++++++++++++---
+ drivers/usb/serial/opticon.c          |   14 ++++++++---
+ 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/symbolserial.c     |   14 ++++++++---
+ 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 ++++++---
+ 37 files changed, 319 insertions(+), 200 deletions(-)
+
+--- a/drivers/staging/uc2322/aten2011.c
++++ b/drivers/staging/uc2322/aten2011.c
+@@ -2336,7 +2336,7 @@ static int ATEN2011_startup(struct usb_s
+       return 0;
+ }
+-static void ATEN2011_shutdown(struct usb_serial *serial)
++static void ATEN2011_release(struct usb_serial *serial)
+ {
+       int i;
+       struct ATENINTL_port *ATEN2011_port;
+@@ -2382,7 +2382,7 @@ static struct usb_serial_driver aten_ser
+       .tiocmget =             ATEN2011_tiocmget,
+       .tiocmset =             ATEN2011_tiocmset,
+       .attach =               ATEN2011_startup,
+-      .shutdown =             ATEN2011_shutdown,
++      .release =              ATEN2011_release,
+       .read_bulk_callback =   ATEN2011_bulk_in_callback,
+       .read_int_callback =    ATEN2011_interrupt_callback,
+ };
+--- a/drivers/usb/serial/aircable.c
++++ b/drivers/usb/serial/aircable.c
+@@ -364,7 +364,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];
+@@ -375,7 +375,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);
+       }
+ }
+@@ -601,7 +600,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/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -51,7 +51,7 @@ static int cp2101_tiocmset_port(struct u
+               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;
+@@ -131,7 +131,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 */
+@@ -773,7 +773,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,
+@@ -149,17 +151,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,
+@@ -613,7 +613,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;
+@@ -626,7 +626,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,
+ };
+@@ -1589,16 +1592,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
+@@ -91,7 +91,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);
+@@ -125,7 +124,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
+@@ -714,7 +714,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,
+@@ -770,7 +769,6 @@ static struct usb_serial_driver ftdi_sio
+       .ioctl =                ftdi_ioctl,
+       .set_termios =          ftdi_set_termios,
+       .break_ctl =            ftdi_break_ctl,
+-      .shutdown =             ftdi_shutdown,
+ };
+@@ -1460,18 +1458,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 void ftdi_sio_priv_release(struct kref *k)
+ {
+       struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
+--- a/drivers/usb/serial/garmin_gps.c
++++ b/drivers/usb/serial/garmin_gps.c
+@@ -1528,7 +1528,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);
+@@ -1537,8 +1537,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);
+ }
+@@ -1557,7 +1566,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,
+@@ -413,7 +414,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;
+@@ -424,3 +425,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 */
+@@ -3195,21 +3196,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);
+@@ -3220,9 +3216,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
+@@ -2664,7 +2664,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;
+@@ -2674,12 +2674,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);
+ }
+@@ -2916,7 +2926,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,
+@@ -2945,7 +2956,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
+@@ -80,7 +80,6 @@ static void ipaq_close(struct tty_struct
+                       struct usb_serial_port *port, struct file *filp);
+ static int  ipaq_calc_num_ports(struct usb_serial *serial);
+ 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,
+@@ -577,7 +576,6 @@ static struct usb_serial_driver ipaq_dev
+       .close =                ipaq_close,
+       .attach =               ipaq_startup,
+       .calc_num_ports =       ipaq_calc_num_ports,
+-      .shutdown =             ipaq_shutdown,
+       .write =                ipaq_write,
+       .write_room =           ipaq_write_room,
+       .chars_in_buffer =      ipaq_chars_in_buffer,
+@@ -992,11 +990,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);
+@@ -1176,7 +1176,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
+@@ -2682,7 +2682,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;
+@@ -2722,6 +2722,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
+@@ -795,7 +795,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__);
+@@ -853,7 +853,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,
+ };
+@@ -316,7 +318,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;
+@@ -326,33 +328,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,
+ };
+@@ -406,7 +406,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;
+@@ -416,12 +416,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
+@@ -1522,19 +1522,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 = {
+@@ -1559,7 +1556,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
+@@ -2673,16 +2673,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");
+@@ -2702,11 +2702,42 @@ 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);
++              }
++      }
++
++      dbg("%s", "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", " 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);
+               }
+-              mos7840_set_port_private(serial->port[i], NULL);
+       }
+       dbg("%s\n", "Thank u :: ");
+@@ -2747,7 +2778,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,
+ };
+@@ -347,13 +349,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/opticon.c
++++ b/drivers/usb/serial/opticon.c
+@@ -464,7 +464,7 @@ error:
+       return retval;
+ }
+-static void opticon_shutdown(struct usb_serial *serial)
++static void opticon_disconnect(struct usb_serial *serial)
+ {
+       struct opticon_private *priv = usb_get_serial_data(serial);
+@@ -472,9 +472,16 @@ static void opticon_shutdown(struct usb_
+       usb_kill_urb(priv->bulk_read_urb);
+       usb_free_urb(priv->bulk_read_urb);
++}
++
++static void opticon_release(struct usb_serial *serial)
++{
++      struct opticon_private *priv = usb_get_serial_data(serial);
++
++      dbg("%s", __func__);
++
+       kfree(priv->bulk_in_buffer);
+       kfree(priv);
+-      usb_set_serial_data(serial, NULL);
+ }
+ static int opticon_suspend(struct usb_interface *intf, pm_message_t message)
+@@ -525,7 +532,8 @@ static struct usb_serial_driver opticon_
+       .close =                opticon_close,
+       .write =                opticon_write,
+       .write_room =           opticon_write_room,
+-      .shutdown =             opticon_shutdown,
++      .disconnect =           opticon_disconnect,
++      .release =              opticon_release,
+       .throttle =             opticon_throttle,
+       .unthrottle =           opticon_unthrottle,
+       .ioctl =                opticon_ioctl,
+--- 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);
+@@ -558,7 +559,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,
+@@ -1129,7 +1131,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;
+@@ -1137,8 +1146,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 {
+@@ -829,7 +829,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;
+@@ -841,7 +841,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
+@@ -897,7 +897,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;
+@@ -909,7 +909,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);
+               }
+       }
+ }
+@@ -1137,7 +1136,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
+@@ -699,7 +699,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;
+@@ -718,10 +718,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);
+       }
+ }
+@@ -743,7 +762,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);
+               }
+       }
+ }
+@@ -1043,7 +1042,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/symbolserial.c
++++ b/drivers/usb/serial/symbolserial.c
+@@ -268,7 +268,7 @@ error:
+       return retval;
+ }
+-static void symbol_shutdown(struct usb_serial *serial)
++static void symbol_disconnect(struct usb_serial *serial)
+ {
+       struct symbol_private *priv = usb_get_serial_data(serial);
+@@ -276,9 +276,16 @@ static void symbol_shutdown(struct usb_s
+       usb_kill_urb(priv->int_urb);
+       usb_free_urb(priv->int_urb);
++}
++
++static void symbol_release(struct usb_serial *serial)
++{
++      struct symbol_private *priv = usb_get_serial_data(serial);
++
++      dbg("%s", __func__);
++
+       kfree(priv->int_buffer);
+       kfree(priv);
+-      usb_set_serial_data(serial, NULL);
+ }
+ static struct usb_driver symbol_driver = {
+@@ -300,7 +307,8 @@ static struct usb_serial_driver symbol_d
+       .attach =               symbol_startup,
+       .open =                 symbol_open,
+       .close =                symbol_close,
+-      .shutdown =             symbol_shutdown,
++      .disconnect =           symbol_disconnect,
++      .release =              symbol_release,
+       .throttle =             symbol_throttle,
+       .unthrottle =           symbol_unthrottle,
+ };
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -97,7 +97,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,
+@@ -231,7 +231,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,
+@@ -259,7 +259,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,
+@@ -474,7 +474,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);
+@@ -487,12 +487,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
+@@ -141,6 +141,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 */
+@@ -148,9 +156,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);
+               }
+       }
+@@ -1062,10 +1069,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) {
+@@ -1079,14 +1082,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 */
+@@ -1262,7 +1258,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);
+ }
+ int usb_serial_register(struct usb_serial_driver *driver)
+--- 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,
+@@ -920,7 +920,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;
+@@ -929,10 +929,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,
+@@ -618,7 +618,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
+@@ -181,8 +181,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.
+@@ -212,7 +214,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);
+@@ -292,7 +295,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);