]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
usb patches for .31
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 15 Oct 2009 17:37:02 +0000 (10:37 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 15 Oct 2009 17:37:02 +0000 (10:37 -0700)
queue-2.6.31/series
queue-2.6.31/usb-cp210x-add-support-for-the-dw700-uart.patch [new file with mode: 0644]
queue-2.6.31/usb-digi_acceleport-fix-broken-unthrottle.patch [new file with mode: 0644]
queue-2.6.31/usb-fix-throttling-in-generic-usbserial-driver.patch [new file with mode: 0644]
queue-2.6.31/usb-ftdi_sio-clean-up-read-completion-handler.patch [new file with mode: 0644]
queue-2.6.31/usb-ftdi_sio-re-implement-read-processing.patch [new file with mode: 0644]
queue-2.6.31/usb-ipaq-fix-oops-when-device-is-plugged-in.patch [new file with mode: 0644]
queue-2.6.31/usb-option-toshiba-g450-device-id.patch [new file with mode: 0644]
queue-2.6.31/usb-pl2303-fix-error-characters-not-being-reported-to-ldisc.patch [new file with mode: 0644]
queue-2.6.31/usb-serial-don-t-call-release-without-attach.patch [new file with mode: 0644]
queue-2.6.31/usb-storage-when-a-device-returns-no-sense-data-call-it-a-hardware-error.patch [new file with mode: 0644]

index 702dd1e5e8633fc3839dd32c833468a0ce9e6de4..10d3638f4db7a34b58f6691ec894570356012d57 100644 (file)
@@ -6,3 +6,13 @@ tracing-filters-fix-memory-leak-when-setting-a-filter.patch
 x86-paravirt-use-normal-calling-sequences-for-irq-enable-disable.patch
 usb-ftdi_sio-remove-tty-low_latency.patch
 usb-ftdi_sio-remove-unused-rx_byte-counter.patch
+usb-ftdi_sio-clean-up-read-completion-handler.patch
+usb-ftdi_sio-re-implement-read-processing.patch
+usb-pl2303-fix-error-characters-not-being-reported-to-ldisc.patch
+usb-digi_acceleport-fix-broken-unthrottle.patch
+usb-serial-don-t-call-release-without-attach.patch
+usb-option-toshiba-g450-device-id.patch
+usb-ipaq-fix-oops-when-device-is-plugged-in.patch
+usb-cp210x-add-support-for-the-dw700-uart.patch
+usb-fix-throttling-in-generic-usbserial-driver.patch
+usb-storage-when-a-device-returns-no-sense-data-call-it-a-hardware-error.patch
diff --git a/queue-2.6.31/usb-cp210x-add-support-for-the-dw700-uart.patch b/queue-2.6.31/usb-cp210x-add-support-for-the-dw700-uart.patch
new file mode 100644 (file)
index 0000000..1f4bcb2
--- /dev/null
@@ -0,0 +1,33 @@
+From 6f88139eb9eae8003683689f93402264a73fb754 Mon Sep 17 00:00:00 2001
+From: Éric Piel <eric.piel@tremplin-utc.net>
+Date: Sun, 4 Oct 2009 13:45:07 +0200
+Subject: USB: cp210x: Add support for the DW700 UART
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Éric Piel <eric.piel@tremplin-utc.net>
+
+commit 6f88139eb9eae8003683689f93402264a73fb754 upstream.
+
+In the Dell inspiron mini 10, the GPS is connected via a cp2102. This patch
+adds detection of this USB device. (I haven't managed to use the GPS under
+Linux yet, though)
+
+Signed-off-by: Éric Piel <eric.piel@tremplin-utc.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/cp210x.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -114,6 +114,7 @@ static struct usb_device_id id_table [] 
+       { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
+       { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+       { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
++      { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
+       { } /* Terminating Entry */
+ };
diff --git a/queue-2.6.31/usb-digi_acceleport-fix-broken-unthrottle.patch b/queue-2.6.31/usb-digi_acceleport-fix-broken-unthrottle.patch
new file mode 100644 (file)
index 0000000..c88e674
--- /dev/null
@@ -0,0 +1,43 @@
+From ba6b702f85a61561d329c4c11d3ed95604924f9a Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Tue, 29 Sep 2009 12:39:23 +0200
+Subject: USB: digi_acceleport: Fix broken unthrottle.
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit ba6b702f85a61561d329c4c11d3ed95604924f9a upstream.
+
+This patch fixes a regression introduced in
+39892da44b21b5362eb848ca424d73a25ccc488f.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Acked-by: Oliver Neukum <oliver@neukum.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/digi_acceleport.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -899,16 +899,16 @@ static void digi_rx_unthrottle(struct tt
+       spin_lock_irqsave(&priv->dp_port_lock, flags);
+-      /* turn throttle off */
+-      priv->dp_throttled = 0;
+-      priv->dp_throttle_restart = 0;
+-
+       /* restart read chain */
+       if (priv->dp_throttle_restart) {
+               port->read_urb->dev = port->serial->dev;
+               ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       }
++      /* turn throttle off */
++      priv->dp_throttled = 0;
++      priv->dp_throttle_restart = 0;
++
+       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+       if (ret)
diff --git a/queue-2.6.31/usb-fix-throttling-in-generic-usbserial-driver.patch b/queue-2.6.31/usb-fix-throttling-in-generic-usbserial-driver.patch
new file mode 100644 (file)
index 0000000..acdacf5
--- /dev/null
@@ -0,0 +1,33 @@
+From 63a9609513007537a0b23ac511fd73f9bd609ea0 Mon Sep 17 00:00:00 2001
+From: Joris van Rantwijk <jorispubl@xs4all.nl>
+Date: Thu, 24 Sep 2009 20:20:20 +0200
+Subject: USB: Fix throttling in generic usbserial driver
+
+From: Joris van Rantwijk <jorispubl@xs4all.nl>
+
+commit 63a9609513007537a0b23ac511fd73f9bd609ea0 upstream.
+
+The generic usbserial driver in Linux 2.6.31 halts its receiving
+channel in response to throttle requests from the line discipline.
+Unfortunately it drops the contents of the first URB received after
+throttling takes effect. This patch corrects that problem.
+
+Signed-off-by: Joris van Rantwijk <jorispubl@xs4all.nl>
+Acked-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/generic.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -530,7 +530,7 @@ void usb_serial_generic_unthrottle(struc
+       if (was_throttled) {
+               /* Resume reading from device */
+-              usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
++              flush_and_resubmit_read_urb(port);
+       }
+ }
diff --git a/queue-2.6.31/usb-ftdi_sio-clean-up-read-completion-handler.patch b/queue-2.6.31/usb-ftdi_sio-clean-up-read-completion-handler.patch
new file mode 100644 (file)
index 0000000..bb25158
--- /dev/null
@@ -0,0 +1,80 @@
+From e63e278b4d2d867893962d3c7cd13a3a24ceb3f1 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 7 Oct 2009 20:05:06 +0200
+Subject: USB: ftdi_sio: clean up read completion handler
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit e63e278b4d2d867893962d3c7cd13a3a24ceb3f1 upstream.
+
+Remove superfluous error checks in completion handler:
+
+ - No need to check private data and urb pointers as we check urb-status
+   before dereferencing priv (which is not freed until urb has been killed
+   on close).
+ - No need to check tty as it is checked again when processing.
+ - No need to check urb->number_of_packets on bulk urb.
+
+Note that both private data and tty are checked again before processing
+(possibly from work queue which also is cancelled on close).
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/ftdi_sio.c |   28 +---------------------------
+ 1 file changed, 1 insertion(+), 27 deletions(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -2010,39 +2010,14 @@ static int ftdi_chars_in_buffer(struct t
+ static void ftdi_read_bulk_callback(struct urb *urb)
+ {
+       struct usb_serial_port *port = urb->context;
+-      struct tty_struct *tty;
+       struct ftdi_private *priv;
+       int status = urb->status;
+-      if (urb->number_of_packets > 0) {
+-              dev_err(&port->dev, "%s transfer_buffer_length %d "
+-                      "actual_length %d number of packets %d\n", __func__,
+-                      urb->transfer_buffer_length,
+-                      urb->actual_length, urb->number_of_packets);
+-              dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
+-                      urb->transfer_flags);
+-      }
+-
+       dbg("%s - port %d", __func__, port->number);
+       if (port->port.count <= 0)
+               return;
+-      tty = tty_port_tty_get(&port->port);
+-      if (!tty) {
+-              dbg("%s - bad tty pointer - exiting", __func__);
+-              return;
+-      }
+-
+-      priv = usb_get_serial_port_data(port);
+-      if (!priv) {
+-              dbg("%s - bad port private data pointer - exiting", __func__);
+-              goto out;
+-      }
+-
+-      if (urb != port->read_urb)
+-              dev_err(&port->dev, "%s - Not my urb!\n", __func__);
+-
+       if (status) {
+               /* This will happen at close every time so it is a dbg not an
+                  err */
+@@ -2050,9 +2025,8 @@ static void ftdi_read_bulk_callback(stru
+               goto out;
+       }
++      priv = usb_get_serial_port_data(port);
+       ftdi_process_read(&priv->rx_work.work);
+-out:
+-      tty_kref_put(tty);
+ } /* ftdi_read_bulk_callback */
diff --git a/queue-2.6.31/usb-ftdi_sio-re-implement-read-processing.patch b/queue-2.6.31/usb-ftdi_sio-re-implement-read-processing.patch
new file mode 100644 (file)
index 0000000..5a9b865
--- /dev/null
@@ -0,0 +1,521 @@
+From cc01f17d5cb8ac604108515735aeca72e17944c1 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 7 Oct 2009 20:05:07 +0200
+Subject: USB: ftdi_sio: re-implement read processing
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit cc01f17d5cb8ac604108515735aeca72e17944c1 upstream.
+
+- Re-structure read processing.
+ - Kill obsolete work queue and always push to tty in completion handler.
+ - Use tty_insert_flip_string instead of per character push when
+   possible.
+ - Fix stalled-read regression in 2.6.31 by using urb status to
+   determine when port is closed rather than port count.
+ - Fix race with open/close by checking ASYNCB_INITIALIZED in
+   unthrottle.
+ - Kill private rx_flag and lock and use throttle flags in
+   usb_serial_port instead.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/ftdi_sio.c |  383 ++++++++++++++----------------------------
+ 1 file changed, 131 insertions(+), 252 deletions(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -76,12 +76,7 @@ struct ftdi_private {
+       unsigned long last_dtr_rts;     /* saved modem control outputs */
+       wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
+-      __u8 rx_flags;          /* receive state flags (throttling) */
+-      spinlock_t rx_lock;     /* spinlock for receive state */
+-      struct delayed_work rx_work;
+       struct usb_serial_port *port;
+-      int rx_processed;
+-
+       __u16 interface;        /* FT2232C, FT2232H or FT4232H port interface
+                                  (0 for FT232/245) */
+@@ -736,10 +731,6 @@ static const char *ftdi_chip_name[] = {
+ /* Constants for read urb and write urb */
+ #define BUFSZ 512
+-/* rx_flags */
+-#define THROTTLED             0x01
+-#define ACTUALLY_THROTTLED    0x02
+-
+ /* Used for TIOCMIWAIT */
+ #define FTDI_STATUS_B0_MASK   (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
+ #define FTDI_STATUS_B1_MASK   (FTDI_RS_BI)
+@@ -763,7 +754,7 @@ static int  ftdi_write_room(struct tty_s
+ static int  ftdi_chars_in_buffer(struct tty_struct *tty);
+ static void ftdi_write_bulk_callback(struct urb *urb);
+ static void ftdi_read_bulk_callback(struct urb *urb);
+-static void ftdi_process_read(struct work_struct *work);
++static void ftdi_process_read(struct usb_serial_port *port);
+ static void ftdi_set_termios(struct tty_struct *tty,
+                       struct usb_serial_port *port, struct ktermios *old);
+ static int  ftdi_tiocmget(struct tty_struct *tty, struct file *file);
+@@ -1526,7 +1517,6 @@ static int ftdi_sio_port_probe(struct us
+       }
+       kref_init(&priv->kref);
+-      spin_lock_init(&priv->rx_lock);
+       spin_lock_init(&priv->tx_lock);
+       init_waitqueue_head(&priv->delta_msr_wait);
+       /* This will push the characters through immediately rather
+@@ -1548,7 +1538,6 @@ static int ftdi_sio_port_probe(struct us
+               port->read_urb->transfer_buffer_length = BUFSZ;
+       }
+-      INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read);
+       priv->port = port;
+       /* Free port's existing write urb and transfer buffer. */
+@@ -1685,6 +1674,26 @@ static int ftdi_sio_port_remove(struct u
+       return 0;
+ }
++static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
++{
++      struct urb *urb = port->read_urb;
++      struct usb_serial *serial = port->serial;
++      int result;
++
++      usb_fill_bulk_urb(urb, serial->dev,
++                         usb_rcvbulkpipe(serial->dev,
++                                      port->bulk_in_endpointAddress),
++                         urb->transfer_buffer,
++                         urb->transfer_buffer_length,
++                         ftdi_read_bulk_callback, port);
++      result = usb_submit_urb(urb, mem_flags);
++      if (result)
++              dev_err(&port->dev,
++                      "%s - failed submitting read urb, error %d\n",
++                                                      __func__, result);
++      return result;
++}
++
+ static int ftdi_open(struct tty_struct *tty,
+                       struct usb_serial_port *port, struct file *filp)
+ { /* ftdi_open */
+@@ -1719,23 +1728,14 @@ static int ftdi_open(struct tty_struct *
+               ftdi_set_termios(tty, port, tty->termios);
+       /* Not throttled */
+-      spin_lock_irqsave(&priv->rx_lock, flags);
+-      priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+-      spin_unlock_irqrestore(&priv->rx_lock, flags);
++      spin_lock_irqsave(&port->lock, flags);
++      port->throttled = 0;
++      port->throttle_req = 0;
++      spin_unlock_irqrestore(&port->lock, flags);
+       /* Start reading from the device */
+-      priv->rx_processed = 0;
+-      usb_fill_bulk_urb(port->read_urb, dev,
+-                      usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
+-                      port->read_urb->transfer_buffer,
+-                              port->read_urb->transfer_buffer_length,
+-                      ftdi_read_bulk_callback, port);
+-      result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+-      if (result)
+-              dev_err(&port->dev,
+-                      "%s - failed submitting read urb, error %d\n",
+-                      __func__, result);
+-      else
++      result = ftdi_submit_read_urb(port, GFP_KERNEL);
++      if (!result)
+               kref_get(&priv->kref);
+       return result;
+@@ -1781,10 +1781,6 @@ static void ftdi_close(struct usb_serial
+       dbg("%s", __func__);
+-
+-      /* cancel any scheduled reading */
+-      cancel_delayed_work_sync(&priv->rx_work);
+-
+       /* shutdown our bulk read */
+       usb_kill_urb(port->read_urb);
+       kref_put(&priv->kref, ftdi_sio_priv_release);
+@@ -2007,236 +2003,121 @@ static int ftdi_chars_in_buffer(struct t
+       return buffered;
+ }
+-static void ftdi_read_bulk_callback(struct urb *urb)
++static int ftdi_process_packet(struct tty_struct *tty,
++              struct usb_serial_port *port, struct ftdi_private *priv,
++              char *packet, int len)
+ {
+-      struct usb_serial_port *port = urb->context;
+-      struct ftdi_private *priv;
+-      int status = urb->status;
+-
+-      dbg("%s - port %d", __func__, port->number);
+-
+-      if (port->port.count <= 0)
+-              return;
+-
+-      if (status) {
+-              /* This will happen at close every time so it is a dbg not an
+-                 err */
+-              dbg("(this is ok on close) nonzero read bulk status received: %d", status);
+-              goto out;
+-      }
+-
+-      priv = usb_get_serial_port_data(port);
+-      ftdi_process_read(&priv->rx_work.work);
+-} /* ftdi_read_bulk_callback */
+-
+-
+-static void ftdi_process_read(struct work_struct *work)
+-{ /* ftdi_process_read */
+-      struct ftdi_private *priv =
+-              container_of(work, struct ftdi_private, rx_work.work);
+-      struct usb_serial_port *port = priv->port;
+-      struct urb *urb;
+-      struct tty_struct *tty;
+-      char error_flag;
+-      unsigned char *data;
+-
+       int i;
+-      int result;
+-      int need_flip;
+-      int packet_offset;
+-      unsigned long flags;
++      char status;
++      char flag;
++      char *ch;
+       dbg("%s - port %d", __func__, port->number);
+-      if (port->port.count <= 0)
+-              return;
+-
+-      tty = tty_port_tty_get(&port->port);
+-      if (!tty) {
+-              dbg("%s - bad tty pointer - exiting", __func__);
+-              return;
++      if (len < 2) {
++              dbg("malformed packet");
++              return 0;
+       }
+-      priv = usb_get_serial_port_data(port);
+-      if (!priv) {
+-              dbg("%s - bad port private data pointer - exiting", __func__);
+-              goto out;
++      /* Compare new line status to the old one, signal if different/
++         N.B. packet may be processed more than once, but differences
++         are only processed once.  */
++      status = packet[0] & FTDI_STATUS_B0_MASK;
++      if (status != priv->prev_status) {
++              priv->diff_status |= status ^ priv->prev_status;
++              wake_up_interruptible(&priv->delta_msr_wait);
++              priv->prev_status = status;
+       }
+-      urb = port->read_urb;
+-      if (!urb) {
+-              dbg("%s - bad read_urb pointer - exiting", __func__);
+-              goto out;
++      /*
++       * Although the device uses a bitmask and hence can have multiple
++       * errors on a packet - the order here sets the priority the error is
++       * returned to the tty layer.
++       */
++      flag = TTY_NORMAL;
++      if (packet[1] & FTDI_RS_OE) {
++              flag = TTY_OVERRUN;
++              dbg("OVERRRUN error");
+       }
+-
+-      data = urb->transfer_buffer;
+-
+-      if (priv->rx_processed) {
+-              dbg("%s - already processed: %d bytes, %d remain", __func__,
+-                              priv->rx_processed,
+-                              urb->actual_length - priv->rx_processed);
+-      } else {
+-              /* The first two bytes of every read packet are status */
+-              if (urb->actual_length > 2)
+-                      usb_serial_debug_data(debug, &port->dev, __func__,
+-                                              urb->actual_length, data);
+-              else
+-                      dbg("Status only: %03oo %03oo", data[0], data[1]);
++      if (packet[1] & FTDI_RS_BI) {
++              flag = TTY_BREAK;
++              dbg("BREAK received");
++              usb_serial_handle_break(port);
++      }
++      if (packet[1] & FTDI_RS_PE) {
++              flag = TTY_PARITY;
++              dbg("PARITY error");
++      }
++      if (packet[1] & FTDI_RS_FE) {
++              flag = TTY_FRAME;
++              dbg("FRAMING error");
+       }
++      len -= 2;
++      if (!len)
++              return 0;       /* status only */
++      ch = packet + 2;
+-      /* TO DO -- check for hung up line and handle appropriately: */
+-      /*   send hangup  */
+-      /* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
+-      /* if CD is dropped and the line is not CLOCAL then we should hangup */
+-
+-      need_flip = 0;
+-      for (packet_offset = priv->rx_processed;
+-              packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
+-              int length;
+-
+-              /* Compare new line status to the old one, signal if different/
+-                 N.B. packet may be processed more than once, but differences
+-                 are only processed once.  */
+-              char new_status = data[packet_offset + 0] &
+-                                              FTDI_STATUS_B0_MASK;
+-              if (new_status != priv->prev_status) {
+-                      priv->diff_status |=
+-                              new_status ^ priv->prev_status;
+-                      wake_up_interruptible(&priv->delta_msr_wait);
+-                      priv->prev_status = new_status;
+-              }
+-
+-              length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
+-              if (length < 0) {
+-                      dev_err(&port->dev, "%s - bad packet length: %d\n",
+-                              __func__, length+2);
+-                      length = 0;
++      if (!(port->console && port->sysrq) && flag == TTY_NORMAL)
++              tty_insert_flip_string(tty, ch, len);
++      else {
++              for (i = 0; i < len; i++, ch++) {
++                      if (!usb_serial_handle_sysrq_char(tty, port, *ch))
++                              tty_insert_flip_char(tty, *ch, flag);
+               }
++      }
++      return len;
++}
+-              if (priv->rx_flags & THROTTLED) {
+-                      dbg("%s - throttled", __func__);
+-                      break;
+-              }
+-              if (tty_buffer_request_room(tty, length) < length) {
+-                      /* break out & wait for throttling/unthrottling to
+-                         happen */
+-                      dbg("%s - receive room low", __func__);
+-                      break;
+-              }
++static void ftdi_process_read(struct usb_serial_port *port)
++{
++      struct urb *urb = port->read_urb;
++      struct tty_struct *tty;
++      struct ftdi_private *priv = usb_get_serial_port_data(port);
++      char *data = (char *)urb->transfer_buffer;
++      int i;
++      int len;
++      int count = 0;
+-              /* Handle errors and break */
+-              error_flag = TTY_NORMAL;
+-              /* Although the device uses a bitmask and hence can have
+-                 multiple errors on a packet - the order here sets the
+-                 priority the error is returned to the tty layer  */
+-
+-              if (data[packet_offset+1] & FTDI_RS_OE) {
+-                      error_flag = TTY_OVERRUN;
+-                      dbg("OVERRRUN error");
+-              }
+-              if (data[packet_offset+1] & FTDI_RS_BI) {
+-                      error_flag = TTY_BREAK;
+-                      dbg("BREAK received");
+-                      usb_serial_handle_break(port);
+-              }
+-              if (data[packet_offset+1] & FTDI_RS_PE) {
+-                      error_flag = TTY_PARITY;
+-                      dbg("PARITY error");
+-              }
+-              if (data[packet_offset+1] & FTDI_RS_FE) {
+-                      error_flag = TTY_FRAME;
+-                      dbg("FRAMING error");
+-              }
+-              if (length > 0) {
+-                      for (i = 2; i < length+2; i++) {
+-                              /* Note that the error flag is duplicated for
+-                                 every character received since we don't know
+-                                 which character it applied to */
+-                              if (!usb_serial_handle_sysrq_char(tty, port,
+-                                              data[packet_offset + i]))
+-                                      tty_insert_flip_char(tty,
+-                                              data[packet_offset + i],
+-                                              error_flag);
+-                      }
+-                      need_flip = 1;
+-              }
++      tty = tty_port_tty_get(&port->port);
++      if (!tty)
++              return;
+-#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
+-              /* if a parity error is detected you get status packets forever
+-                 until a character is sent without a parity error.
+-                 This doesn't work well since the application receives a
+-                 never ending stream of bad data - even though new data
+-                 hasn't been sent. Therefore I (bill) have taken this out.
+-                 However - this might make sense for framing errors and so on
+-                 so I am leaving the code in for now.
+-              */
+-              else {
+-                      if (error_flag != TTY_NORMAL) {
+-                              dbg("error_flag is not normal");
+-                              /* In this case it is just status - if that is
+-                                 an error send a bad character */
+-                              if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+-                                      tty_flip_buffer_push(tty);
+-                              tty_insert_flip_char(tty, 0xff, error_flag);
+-                              need_flip = 1;
+-                      }
+-              }
+-#endif
+-      } /* "for(packet_offset=0..." */
++      for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
++              len = min_t(int, urb->actual_length - i, priv->max_packet_size);
++              count += ftdi_process_packet(tty, port, priv, &data[i], len);
++      }
+-      /* Low latency */
+-      if (need_flip)
++      if (count)
+               tty_flip_buffer_push(tty);
++      tty_kref_put(tty);
++}
+-      if (packet_offset < urb->actual_length) {
+-              /* not completely processed - record progress */
+-              priv->rx_processed = packet_offset;
+-              dbg("%s - incomplete, %d bytes processed, %d remain",
+-                              __func__, packet_offset,
+-                              urb->actual_length - packet_offset);
+-              /* check if we were throttled while processing */
+-              spin_lock_irqsave(&priv->rx_lock, flags);
+-              if (priv->rx_flags & THROTTLED) {
+-                      priv->rx_flags |= ACTUALLY_THROTTLED;
+-                      spin_unlock_irqrestore(&priv->rx_lock, flags);
+-                      dbg("%s - deferring remainder until unthrottled",
+-                                      __func__);
+-                      goto out;
+-              }
+-              spin_unlock_irqrestore(&priv->rx_lock, flags);
+-              /* if the port is closed stop trying to read */
+-              if (port->port.count > 0)
+-                      /* delay processing of remainder */
+-                      schedule_delayed_work(&priv->rx_work, 1);
+-              else
+-                      dbg("%s - port is closed", __func__);
+-              goto out;
+-      }
+-
+-      /* urb is completely processed */
+-      priv->rx_processed = 0;
++static void ftdi_read_bulk_callback(struct urb *urb)
++{
++      struct usb_serial_port *port = urb->context;
++      unsigned long flags;
+-      /* if the port is closed stop trying to read */
+-      if (port->port.count > 0) {
+-              /* Continue trying to always read  */
+-              usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+-                      usb_rcvbulkpipe(port->serial->dev,
+-                                      port->bulk_in_endpointAddress),
+-                      port->read_urb->transfer_buffer,
+-                      port->read_urb->transfer_buffer_length,
+-                      ftdi_read_bulk_callback, port);
++      dbg("%s - port %d", __func__, port->number);
+-              result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+-              if (result)
+-                      dev_err(&port->dev,
+-                              "%s - failed resubmitting read urb, error %d\n",
+-                              __func__, result);
++      if (urb->status) {
++              dbg("%s - nonzero read bulk status received: %d",
++                                              __func__, urb->status);
++              return;
+       }
+-out:
+-      tty_kref_put(tty);
+-} /* ftdi_process_read */
++      usb_serial_debug_data(debug, &port->dev, __func__,
++                              urb->actual_length, urb->transfer_buffer);
++      ftdi_process_read(port);
++
++      spin_lock_irqsave(&port->lock, flags);
++      port->throttled = port->throttle_req;
++      if (!port->throttled) {
++              spin_unlock_irqrestore(&port->lock, flags);
++              ftdi_submit_read_urb(port, GFP_ATOMIC);
++      } else
++              spin_unlock_irqrestore(&port->lock, flags);
++}
+ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
+ {
+@@ -2568,33 +2449,31 @@ static int ftdi_ioctl(struct tty_struct 
+ static void ftdi_throttle(struct tty_struct *tty)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+-      struct ftdi_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       dbg("%s - port %d", __func__, port->number);
+-      spin_lock_irqsave(&priv->rx_lock, flags);
+-      priv->rx_flags |= THROTTLED;
+-      spin_unlock_irqrestore(&priv->rx_lock, flags);
++      spin_lock_irqsave(&port->lock, flags);
++      port->throttle_req = 1;
++      spin_unlock_irqrestore(&port->lock, flags);
+ }
+-
+-static void ftdi_unthrottle(struct tty_struct *tty)
++void ftdi_unthrottle(struct tty_struct *tty)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+-      struct ftdi_private *priv = usb_get_serial_port_data(port);
+-      int actually_throttled;
++      int was_throttled;
+       unsigned long flags;
+       dbg("%s - port %d", __func__, port->number);
+-      spin_lock_irqsave(&priv->rx_lock, flags);
+-      actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
+-      priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+-      spin_unlock_irqrestore(&priv->rx_lock, flags);
+-
+-      if (actually_throttled)
+-              schedule_delayed_work(&priv->rx_work, 0);
++      spin_lock_irqsave(&port->lock, flags);
++      was_throttled = port->throttled;
++      port->throttled = port->throttle_req = 0;
++      spin_unlock_irqrestore(&port->lock, flags);
++
++      /* Resubmit urb if throttled and open. */
++      if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
++              ftdi_submit_read_urb(port, GFP_KERNEL);
+ }
+ static int __init ftdi_init(void)
diff --git a/queue-2.6.31/usb-ipaq-fix-oops-when-device-is-plugged-in.patch b/queue-2.6.31/usb-ipaq-fix-oops-when-device-is-plugged-in.patch
new file mode 100644 (file)
index 0000000..45062d1
--- /dev/null
@@ -0,0 +1,41 @@
+From 06bad89da686f6323e95cf925105e8cf88d87caf Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 5 Oct 2009 15:53:58 -0400
+Subject: USB: ipaq: fix oops when device is plugged in
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 06bad89da686f6323e95cf925105e8cf88d87caf upstream.
+
+This patch (as1293) fixes a problem with the ipaq serial driver.  It
+tries to bind to all the interfaces, even those that don't have enough
+endpoints.  The symptom is an invalid memory reference and oops when
+the device is plugged in.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Tested-by: Matthias Geissert <geissert@mathematik.tu-darmstadt.de>
+Tested-by: Tilman Schmidt <tilman@imap.cc>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/ipaq.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/usb/serial/ipaq.c
++++ b/drivers/usb/serial/ipaq.c
+@@ -971,6 +971,15 @@ static int ipaq_calc_num_ports(struct us
+ static int ipaq_startup(struct usb_serial *serial)
+ {
+       dbg("%s", __func__);
++
++      /* Some of the devices in ipaq_id_table[] are composite, and we
++       * shouldn't bind to all the interfaces.  This test will rule out
++       * some obviously invalid possibilities.
++       */
++      if (serial->num_bulk_in < serial->num_ports ||
++                      serial->num_bulk_out < serial->num_ports)
++              return -ENODEV;
++
+       if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
+               /*
+                * FIXME: HP iPaq rx3715, possibly others, have 1 config that
diff --git a/queue-2.6.31/usb-option-toshiba-g450-device-id.patch b/queue-2.6.31/usb-option-toshiba-g450-device-id.patch
new file mode 100644 (file)
index 0000000..77e9a3f
--- /dev/null
@@ -0,0 +1,34 @@
+From 75f47214f90e996eb184eb6e6b0e8b817999c8f7 Mon Sep 17 00:00:00 2001
+From: Peter Magdina <peter@magdina.sk>
+Date: Wed, 7 Oct 2009 16:22:17 +0200
+Subject: USB: option: Toshiba G450 device id
+
+From: Peter Magdina <peter@magdina.sk>
+
+commit 75f47214f90e996eb184eb6e6b0e8b817999c8f7 upstream.
+
+Signed-off-by: Peter Magdina <peter@magdina.sk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/option.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -319,6 +319,7 @@ static int  option_resume(struct usb_ser
+ /* TOSHIBA PRODUCTS */
+ #define TOSHIBA_VENDOR_ID                     0x0930
+ #define TOSHIBA_PRODUCT_HSDPA_MINICARD                0x1302
++#define TOSHIBA_PRODUCT_G450                  0x0d45
+ #define ALINK_VENDOR_ID                               0x1e0e
+ #define ALINK_PRODUCT_3GU                     0x9200
+@@ -582,6 +583,7 @@ static struct usb_device_id option_ids[]
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
+       { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
++      { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
+       { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
+       { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
diff --git a/queue-2.6.31/usb-pl2303-fix-error-characters-not-being-reported-to-ldisc.patch b/queue-2.6.31/usb-pl2303-fix-error-characters-not-being-reported-to-ldisc.patch
new file mode 100644 (file)
index 0000000..5ad28bf
--- /dev/null
@@ -0,0 +1,41 @@
+From 9388e2e71a51fab0aa2309bbb45e8a23d89a95a9 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Thu, 8 Oct 2009 11:36:46 +0200
+Subject: USB: pl2303: fix error characters not being reported to ldisc
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 9388e2e71a51fab0aa2309bbb45e8a23d89a95a9 upstream.
+
+Fix regression introduced by commit
+d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6 (tty: Fix the PL2303 private
+methods for sysrq).
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/pl2303.c |    8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -995,13 +995,15 @@ static void pl2303_push_data(struct tty_
+       /* overrun is special, not associated with a char */
+       if (line_status & UART_OVERRUN_ERROR)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+-      if (port->console && port->sysrq) {
++
++      if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
++              tty_insert_flip_string(tty, data, urb->actual_length);
++      else {
+               int i;
+               for (i = 0; i < urb->actual_length; ++i)
+                       if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
+                               tty_insert_flip_char(tty, data[i], tty_flag);
+-      } else
+-              tty_insert_flip_string(tty, data, urb->actual_length);
++      }
+       tty_flip_buffer_push(tty);
+ }
diff --git a/queue-2.6.31/usb-serial-don-t-call-release-without-attach.patch b/queue-2.6.31/usb-serial-don-t-call-release-without-attach.patch
new file mode 100644 (file)
index 0000000..ea6fcca
--- /dev/null
@@ -0,0 +1,65 @@
+From a4720c650b68a5fe7faed2edeb0ad12645f7ae63 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 9 Oct 2009 12:43:12 -0400
+Subject: USB: serial: don't call release without attach
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit a4720c650b68a5fe7faed2edeb0ad12645f7ae63 upstream.
+
+This patch (as1295) fixes a recently-added bug in the USB serial core.
+If certain kinds of errors occur during probing, the core may call a
+serial driver's release method without previously calling the attach
+method.  This causes some drivers (io_ti in particular) to perform an
+invalid memory access.
+
+The patch adds a new flag to keep track of whether or not attach has
+been called.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Tested-by: Jean-Denis Girard <jd.girard@sysnux.pf>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/usb-serial.c |    6 +++++-
+ include/linux/usb/serial.h      |    1 +
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -155,7 +155,8 @@ static void destroy_serial(struct kref *
+       if (serial->minor != SERIAL_TTY_NO_MINOR)
+               return_serial(serial);
+-      serial->type->release(serial);
++      if (serial->attached)
++              serial->type->release(serial);
+       /* Now that nothing is using the ports, they can be freed */
+       for (i = 0; i < serial->num_port_pointers; ++i) {
+@@ -1060,12 +1061,15 @@ int usb_serial_probe(struct usb_interfac
+               module_put(type->driver.owner);
+               if (retval < 0)
+                       goto probe_error;
++              serial->attached = 1;
+               if (retval > 0) {
+                       /* quietly accept this device, but don't bind to a
+                          serial port as it's about to disappear */
+                       serial->num_ports = 0;
+                       goto exit;
+               }
++      } else {
++              serial->attached = 1;
+       }
+       if (get_free_serial(serial, num_ports, &minor) == NULL) {
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -148,6 +148,7 @@ struct usb_serial {
+       struct usb_interface            *interface;
+       unsigned char                   disconnected:1;
+       unsigned char                   suspending:1;
++      unsigned char                   attached:1;
+       unsigned char                   minor;
+       unsigned char                   num_ports;
+       unsigned char                   num_port_pointers;
diff --git a/queue-2.6.31/usb-storage-when-a-device-returns-no-sense-data-call-it-a-hardware-error.patch b/queue-2.6.31/usb-storage-when-a-device-returns-no-sense-data-call-it-a-hardware-error.patch
new file mode 100644 (file)
index 0000000..3e22bf0
--- /dev/null
@@ -0,0 +1,75 @@
+From f1a0743bc0e7a30c032b1eb78f6a2b0f805b4597 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 6 Oct 2009 14:07:57 -0400
+Subject: USB: storage: When a device returns no sense data, call it a Hardware Error
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit f1a0743bc0e7a30c032b1eb78f6a2b0f805b4597 upstream.
+
+This patch (as1294) fixes a problem that has plagued users for several
+kernel releases.  Some USB mass-storage devices don't return any sense
+data when they encounter certain kinds of errors.  The SCSI layer
+interprets this to mean that the operation should be retried, and the
+same thing happens -- over and over again with no limit.  In some
+circumstances (such as when a bus reset occurs) that is the right
+thing to do, but not here.
+
+The patch checks for this condition (a transport failure with no sense
+data) and changes the result code to DID_ERROR and the sense code to
+Hardware Error.  This does get only a limited number of retries, and
+so the command will fail relatively quickly instead of getting stuck
+in an infinite loop.
+
+This fixes a large part of Bugzilla #14118.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Tested-by: Mantas Mikulenas <grawity@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/transport.c |   29 ++++++++++++++++++++++-------
+ 1 file changed, 22 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/storage/transport.c
++++ b/drivers/usb/storage/transport.c
+@@ -768,17 +768,32 @@ void usb_stor_invoke_transport(struct sc
+               /* set the result so the higher layers expect this data */
+               srb->result = SAM_STAT_CHECK_CONDITION;
+-              /* If things are really okay, then let's show that.  Zero
+-               * out the sense buffer so the higher layers won't realize
+-               * we did an unsolicited auto-sense. */
+-              if (result == USB_STOR_TRANSPORT_GOOD &&
+-                      /* Filemark 0, ignore EOM, ILI 0, no sense */
++              /* We often get empty sense data.  This could indicate that
++               * everything worked or that there was an unspecified
++               * problem.  We have to decide which.
++               */
++              if (    /* Filemark 0, ignore EOM, ILI 0, no sense */
+                               (srb->sense_buffer[2] & 0xaf) == 0 &&
+                       /* No ASC or ASCQ */
+                               srb->sense_buffer[12] == 0 &&
+                               srb->sense_buffer[13] == 0) {
+-                      srb->result = SAM_STAT_GOOD;
+-                      srb->sense_buffer[0] = 0x0;
++
++                      /* If things are really okay, then let's show that.
++                       * Zero out the sense buffer so the higher layers
++                       * won't realize we did an unsolicited auto-sense.
++                       */
++                      if (result == USB_STOR_TRANSPORT_GOOD) {
++                              srb->result = SAM_STAT_GOOD;
++                              srb->sense_buffer[0] = 0x0;
++
++                      /* If there was a problem, report an unspecified
++                       * hardware error to prevent the higher layers from
++                       * entering an infinite retry loop.
++                       */
++                      } else {
++                              srb->result = DID_ERROR << 16;
++                              srb->sense_buffer[2] = HARDWARE_ERROR;
++                      }
+               }
+       }