aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 11:10:12 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 11:10:12 -0700
commit19f23bdac78b23931f45121dd246fedad57597b1 (patch)
treeef45709a56cdf47165ec0acb1eb0377bb2dd9411 /usb
parent3dc984e689eddab9a8624360e8c8eccfc14104bd (diff)
downloadpatches-19f23bdac78b23931f45121dd246fedad57597b1.tar.gz
kobject network namespace patches and some usb serial fixes
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-aircable-fix-incorrect-write-buffer-length.patch28
-rw-r--r--usb/usb-change-the-scatterlist-type-in-struct-urb.patch4
-rw-r--r--usb/usb-clean-up-some-host-controller-sparse-warnings.patch12
-rw-r--r--usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch2
-rw-r--r--usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch32
-rw-r--r--usb/usb-io_ti-remove-unsused-private-counter.patch37
-rw-r--r--usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch349
-rw-r--r--usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch38
-rw-r--r--usb/usb-kl5usb105-fix-memory-leak.patch28
-rw-r--r--usb/usb-kl5usb105-minor-clean-ups.patch228
-rw-r--r--usb/usb-kl5usb105-reimplement-using-generic-framework.patch556
-rw-r--r--usb/usb-musb-update-gfp-slab.h-includes.patch29
-rw-r--r--usb/usb-safe_serial-reimplement-read-using-generic-framework.patch97
-rw-r--r--usb/usb-safe_serial-reimplement-write-using-generic-framework.patch204
-rw-r--r--usb/usb-safe_serial-straighten-out-read-processing.patch82
-rw-r--r--usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch302
-rw-r--r--usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch70
-rw-r--r--usb/usb-xhci-fix-check-for-room-on-the-ring.patch66
-rw-r--r--usb/usb-xhci-fix-compiler-warning.patch2
-rw-r--r--usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch6
-rw-r--r--usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch36
-rw-r--r--usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch2
-rw-r--r--usb/usb-xhci-transfer-ring-link-trb-activation-change.patch12
-rw-r--r--usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch4
24 files changed, 2169 insertions, 57 deletions
diff --git a/usb/usb-aircable-fix-incorrect-write-buffer-length.patch b/usb/usb-aircable-fix-incorrect-write-buffer-length.patch
new file mode 100644
index 00000000000000..c68e04ff1c87a5
--- /dev/null
+++ b/usb/usb-aircable-fix-incorrect-write-buffer-length.patch
@@ -0,0 +1,28 @@
+From jhovold@gmail.com Thu May 20 10:57:22 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:33 +0200
+Subject: USB: aircable: fix incorrect write-buffer length
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-5-git-send-email-jhovold@gmail.com>
+
+
+Returned length should include header length.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/aircable.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/aircable.c
++++ b/drivers/usb/serial/aircable.c
+@@ -95,7 +95,7 @@ static int aircable_prepare_write_buffer
+ buf[1] = TX_HEADER_1;
+ put_unaligned_le16(count, &buf[2]);
+
+- return count;
++ return count + HCI_HEADER_LENGTH;
+ }
+
+ static int aircable_probe(struct usb_serial *serial,
diff --git a/usb/usb-change-the-scatterlist-type-in-struct-urb.patch b/usb/usb-change-the-scatterlist-type-in-struct-urb.patch
index 5a9fc08f9c2922..6c824eff32c6f5 100644
--- a/usb/usb-change-the-scatterlist-type-in-struct-urb.patch
+++ b/usb/usb-change-the-scatterlist-type-in-struct-urb.patch
@@ -114,7 +114,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
void *orig;
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -1771,7 +1771,7 @@ static unsigned int count_sg_trbs_needed
+@@ -1788,7 +1788,7 @@ static unsigned int count_sg_trbs_needed
xhci_dbg(xhci, "count sg list trbs: \n");
num_trbs = 0;
@@ -123,7 +123,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
unsigned int previous_total_trbs = num_trbs;
unsigned int len = sg_dma_len(sg);
-@@ -1934,7 +1934,7 @@ static int queue_bulk_sg_tx(struct xhci_
+@@ -1951,7 +1951,7 @@ static int queue_bulk_sg_tx(struct xhci_
* the amount of memory allocated for this scatter-gather list.
* 3. TRBs buffers can't cross 64KB boundaries.
*/
diff --git a/usb/usb-clean-up-some-host-controller-sparse-warnings.patch b/usb/usb-clean-up-some-host-controller-sparse-warnings.patch
index 132befa10a999c..fef5aec9c95f8e 100644
--- a/usb/usb-clean-up-some-host-controller-sparse-warnings.patch
+++ b/usb/usb-clean-up-some-host-controller-sparse-warnings.patch
@@ -143,7 +143,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -371,7 +371,7 @@ static struct xhci_segment *find_trb_seg
+@@ -388,7 +388,7 @@ static struct xhci_segment *find_trb_seg
cur_seg = cur_seg->next;
if (cur_seg == start_seg)
/* Looped over the entire list. Oops! */
@@ -152,7 +152,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
return cur_seg;
}
-@@ -565,7 +565,7 @@ static void handle_stopped_endpoint(stru
+@@ -582,7 +582,7 @@ static void handle_stopped_endpoint(stru
struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep;
struct list_head *entry;
@@ -161,7 +161,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
struct xhci_td *last_unlinked_td;
struct xhci_dequeue_state deq_state;
-@@ -1098,7 +1098,7 @@ struct xhci_segment *trb_in_td(struct xh
+@@ -1115,7 +1115,7 @@ struct xhci_segment *trb_in_td(struct xh
do {
if (start_dma == 0)
@@ -170,7 +170,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* We may get an event for a Link TRB in the middle of a TD */
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
-@@ -1120,7 +1120,7 @@ struct xhci_segment *trb_in_td(struct xh
+@@ -1137,7 +1137,7 @@ struct xhci_segment *trb_in_td(struct xh
suspect_dma <= end_trb_dma))
return cur_seg;
}
@@ -179,7 +179,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
} else {
/* Might still be somewhere in this segment */
if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
-@@ -1130,7 +1130,7 @@ struct xhci_segment *trb_in_td(struct xh
+@@ -1147,7 +1147,7 @@ struct xhci_segment *trb_in_td(struct xh
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
} while (cur_seg != start_seg);
@@ -188,7 +188,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
-@@ -1206,11 +1206,11 @@ static int handle_tx_event(struct xhci_h
+@@ -1223,11 +1223,11 @@ static int handle_tx_event(struct xhci_h
struct xhci_ring *ep_ring;
unsigned int slot_id;
int ep_index;
diff --git a/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch b/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch
index 7500c711d8dde2..b48f6b4a6d3865 100644
--- a/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch
+++ b/usb/usb-fix-usbmon-and-dma-mapping-for-scatter-gather-urbs.patch
@@ -451,7 +451,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
qset_free_stds(qset, urb);
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -1945,7 +1945,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+@@ -1962,7 +1962,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
int running_total, trb_buff_len, ret;
u64 addr;
diff --git a/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch b/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch
new file mode 100644
index 00000000000000..b7ea1678730034
--- /dev/null
+++ b/usb/usb-ftdi_sio-fix-legacy-sio-device-header.patch
@@ -0,0 +1,32 @@
+From jhovold@gmail.com Thu May 20 10:58:53 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:41 +0200
+Subject: USB: ftdi_sio: fix legacy SIO-device header
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-13-git-send-email-jhovold@gmail.com>
+
+
+Length field of header was incorrectly set to available payload space
+rather than the actual payload size.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/ftdi_sio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1752,10 +1752,10 @@ static int ftdi_prepare_write_buffer(str
+ spin_lock_irqsave(&port->lock, flags);
+ for (i = 0; i < size - 1; i += priv->max_packet_size) {
+ len = min_t(int, size - i, priv->max_packet_size) - 1;
+- buffer[i] = (len << 2) + 1;
+ c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
+ if (!c)
+ break;
++ buffer[i] = (c << 2) + 1;
+ count += c + 1;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
diff --git a/usb/usb-io_ti-remove-unsused-private-counter.patch b/usb/usb-io_ti-remove-unsused-private-counter.patch
new file mode 100644
index 00000000000000..5475aa864c7182
--- /dev/null
+++ b/usb/usb-io_ti-remove-unsused-private-counter.patch
@@ -0,0 +1,37 @@
+From jhovold@gmail.com Thu May 20 10:58:03 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:36 +0200
+Subject: USB: io_ti: remove unsused private counter
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-8-git-send-email-jhovold@gmail.com>
+
+
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/io_ti.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -56,10 +56,6 @@
+ #define EPROM_PAGE_SIZE 64
+
+
+-struct edgeport_uart_buf_desc {
+- __u32 count; /* Number of bytes currently in buffer */
+-};
+-
+ /* different hardware types */
+ #define HARDWARE_TYPE_930 0
+ #define HARDWARE_TYPE_TIUMP 1
+@@ -108,7 +104,6 @@ struct edgeport_port {
+ int baud_rate;
+ int close_pending;
+ int lsr_event;
+- struct edgeport_uart_buf_desc tx;
+ struct async_icount icount;
+ wait_queue_head_t delta_msr_wait; /* for handling sleeping while
+ waiting for msr change to
diff --git a/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch b/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch
new file mode 100644
index 00000000000000..a53a6423df2574
--- /dev/null
+++ b/usb/usb-io_ti-use-kfifo-to-implement-write-buffering.patch
@@ -0,0 +1,349 @@
+From jhovold@gmail.com Thu May 20 10:58:11 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:37 +0200
+Subject: USB: io_ti: use kfifo to implement write buffering
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-9-git-send-email-jhovold@gmail.com>
+
+
+Kill custom fifo implementation.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/io_ti.c | 223 ++-------------------------------------------
+ 1 file changed, 13 insertions(+), 210 deletions(-)
+
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -36,6 +36,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/mutex.h>
+ #include <linux/serial.h>
++#include <linux/kfifo.h>
+ #include <linux/ioctl.h>
+ #include <linux/firmware.h>
+ #include <linux/uaccess.h>
+@@ -83,14 +84,6 @@ struct product_info {
+ __u8 hardware_type; /* Type of hardware */
+ } __attribute__((packed));
+
+-/* circular buffer */
+-struct edge_buf {
+- unsigned int buf_size;
+- char *buf_buf;
+- char *buf_get;
+- char *buf_put;
+-};
+-
+ struct edgeport_port {
+ __u16 uart_base;
+ __u16 dma_address;
+@@ -114,7 +107,7 @@ struct edgeport_port {
+ spinlock_t ep_lock;
+ int ep_read_urb_state;
+ int ep_write_urb_in_use;
+- struct edge_buf *ep_out_buf;
++ struct kfifo write_fifo;
+ };
+
+ struct edgeport_serial {
+@@ -244,17 +237,6 @@ static void edge_send(struct tty_struct
+ static int edge_create_sysfs_attrs(struct usb_serial_port *port);
+ static int edge_remove_sysfs_attrs(struct usb_serial_port *port);
+
+-/* circular buffer */
+-static struct edge_buf *edge_buf_alloc(unsigned int size);
+-static void edge_buf_free(struct edge_buf *eb);
+-static void edge_buf_clear(struct edge_buf *eb);
+-static unsigned int edge_buf_data_avail(struct edge_buf *eb);
+-static unsigned int edge_buf_space_avail(struct edge_buf *eb);
+-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+- unsigned int count);
+-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+- unsigned int count);
+-
+
+ static int ti_vread_sync(struct usb_device *dev, __u8 request,
+ __u16 value, __u16 index, u8 *data, int size)
+@@ -585,7 +567,7 @@ static void chase_port(struct edgeport_p
+ add_wait_queue(&tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+- if (edge_buf_data_avail(port->ep_out_buf) == 0
++ if (kfifo_len(&port->write_fifo) == 0
+ || timeout == 0 || signal_pending(current)
+ || !usb_get_intfdata(port->port->serial->interface))
+ /* disconnect */
+@@ -597,7 +579,7 @@ static void chase_port(struct edgeport_p
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&tty->write_wait, &wait);
+ if (flush)
+- edge_buf_clear(port->ep_out_buf);
++ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&port->ep_lock, flags);
+ tty_kref_put(tty);
+
+@@ -2084,7 +2066,6 @@ static int edge_write(struct tty_struct
+ const unsigned char *data, int count)
+ {
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+- unsigned long flags;
+
+ dbg("%s - port %d", __func__, port->number);
+
+@@ -2098,10 +2079,8 @@ static int edge_write(struct tty_struct
+ if (edge_port->close_pending == 1)
+ return -ENODEV;
+
+- spin_lock_irqsave(&edge_port->ep_lock, flags);
+- count = edge_buf_put(edge_port->ep_out_buf, data, count);
+- spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+-
++ count = kfifo_in_locked(&edge_port->write_fifo, data, count,
++ &edge_port->ep_lock);
+ edge_send(tty);
+
+ return count;
+@@ -2124,7 +2103,7 @@ static void edge_send(struct tty_struct
+ return;
+ }
+
+- count = edge_buf_get(edge_port->ep_out_buf,
++ count = kfifo_out(&edge_port->write_fifo,
+ port->write_urb->transfer_buffer,
+ port->bulk_out_size);
+
+@@ -2180,7 +2159,7 @@ static int edge_write_room(struct tty_st
+ return 0;
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+- room = edge_buf_space_avail(edge_port->ep_out_buf);
++ room = kfifo_avail(&edge_port->write_fifo);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+ dbg("%s - returns %d", __func__, room);
+@@ -2202,7 +2181,7 @@ static int edge_chars_in_buffer(struct t
+ return 0;
+
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+- chars = edge_buf_data_avail(edge_port->ep_out_buf);
++ chars = kfifo_len(&edge_port->write_fifo);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+ dbg("%s - returns %d", __func__, chars);
+@@ -2659,8 +2638,8 @@ static int edge_startup(struct usb_seria
+ goto cleanup;
+ }
+ spin_lock_init(&edge_port->ep_lock);
+- edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
+- if (edge_port->ep_out_buf == NULL) {
++ if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
++ GFP_KERNEL)) {
+ dev_err(&serial->dev->dev, "%s - Out of memory\n",
+ __func__);
+ kfree(edge_port);
+@@ -2677,7 +2656,7 @@ static int edge_startup(struct usb_seria
+ cleanup:
+ for (--i; i >= 0; --i) {
+ edge_port = usb_get_serial_port_data(serial->port[i]);
+- edge_buf_free(edge_port->ep_out_buf);
++ kfifo_free(&edge_port->write_fifo);
+ kfree(edge_port);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+@@ -2708,7 +2687,7 @@ static void edge_release(struct usb_seri
+
+ 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);
++ kfifo_free(&edge_port->write_fifo);
+ kfree(edge_port);
+ }
+ kfree(usb_get_serial_data(serial));
+@@ -2758,182 +2737,6 @@ static int edge_remove_sysfs_attrs(struc
+ }
+
+
+-/* Circular Buffer */
+-
+-/*
+- * edge_buf_alloc
+- *
+- * Allocate a circular buffer and all associated memory.
+- */
+-
+-static struct edge_buf *edge_buf_alloc(unsigned int size)
+-{
+- struct edge_buf *eb;
+-
+-
+- if (size == 0)
+- return NULL;
+-
+- eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
+- if (eb == NULL)
+- return NULL;
+-
+- eb->buf_buf = kmalloc(size, GFP_KERNEL);
+- if (eb->buf_buf == NULL) {
+- kfree(eb);
+- return NULL;
+- }
+-
+- eb->buf_size = size;
+- eb->buf_get = eb->buf_put = eb->buf_buf;
+-
+- return eb;
+-}
+-
+-
+-/*
+- * edge_buf_free
+- *
+- * Free the buffer and all associated memory.
+- */
+-
+-static void edge_buf_free(struct edge_buf *eb)
+-{
+- if (eb) {
+- kfree(eb->buf_buf);
+- kfree(eb);
+- }
+-}
+-
+-
+-/*
+- * edge_buf_clear
+- *
+- * Clear out all data in the circular buffer.
+- */
+-
+-static void edge_buf_clear(struct edge_buf *eb)
+-{
+- if (eb != NULL)
+- eb->buf_get = eb->buf_put;
+- /* equivalent to a get of all data available */
+-}
+-
+-
+-/*
+- * edge_buf_data_avail
+- *
+- * Return the number of bytes of data available in the circular
+- * buffer.
+- */
+-
+-static unsigned int edge_buf_data_avail(struct edge_buf *eb)
+-{
+- if (eb == NULL)
+- return 0;
+- return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size);
+-}
+-
+-
+-/*
+- * edge_buf_space_avail
+- *
+- * Return the number of bytes of space available in the circular
+- * buffer.
+- */
+-
+-static unsigned int edge_buf_space_avail(struct edge_buf *eb)
+-{
+- if (eb == NULL)
+- return 0;
+- return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size);
+-}
+-
+-
+-/*
+- * edge_buf_put
+- *
+- * Copy data data from a user buffer and put it into the circular buffer.
+- * Restrict to the amount of space available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
+- unsigned int count)
+-{
+- unsigned int len;
+-
+-
+- if (eb == NULL)
+- return 0;
+-
+- len = edge_buf_space_avail(eb);
+- if (count > len)
+- count = len;
+-
+- if (count == 0)
+- return 0;
+-
+- len = eb->buf_buf + eb->buf_size - eb->buf_put;
+- if (count > len) {
+- memcpy(eb->buf_put, buf, len);
+- memcpy(eb->buf_buf, buf+len, count - len);
+- eb->buf_put = eb->buf_buf + count - len;
+- } else {
+- memcpy(eb->buf_put, buf, count);
+- if (count < len)
+- eb->buf_put += count;
+- else /* count == len */
+- eb->buf_put = eb->buf_buf;
+- }
+-
+- return count;
+-}
+-
+-
+-/*
+- * edge_buf_get
+- *
+- * Get data from the circular buffer and copy to the given buffer.
+- * Restrict to the amount of data available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
+- unsigned int count)
+-{
+- unsigned int len;
+-
+-
+- if (eb == NULL)
+- return 0;
+-
+- len = edge_buf_data_avail(eb);
+- if (count > len)
+- count = len;
+-
+- if (count == 0)
+- return 0;
+-
+- len = eb->buf_buf + eb->buf_size - eb->buf_get;
+- if (count > len) {
+- memcpy(buf, eb->buf_get, len);
+- memcpy(buf+len, eb->buf_buf, count - len);
+- eb->buf_get = eb->buf_buf + count - len;
+- } else {
+- memcpy(buf, eb->buf_get, count);
+- if (count < len)
+- eb->buf_get += count;
+- else /* count == len */
+- eb->buf_get = eb->buf_buf;
+- }
+-
+- return count;
+-}
+-
+-
+ static struct usb_serial_driver edgeport_1port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
diff --git a/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch b/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch
new file mode 100644
index 00000000000000..b19d435047cffb
--- /dev/null
+++ b/usb/usb-ir-usb-fix-incorrect-write-buffer-length.patch
@@ -0,0 +1,38 @@
+From jhovold@gmail.com Thu May 20 10:57:39 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:34 +0200
+Subject: USB: ir-usb: fix incorrect write-buffer length
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-6-git-send-email-jhovold@gmail.com>
+
+
+Returned length should include header length.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/ir-usb.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/ir-usb.c
++++ b/drivers/usb/serial/ir-usb.c
+@@ -307,6 +307,7 @@ static int ir_prepare_write_buffer(struc
+ void *dest, size_t size)
+ {
+ unsigned char *buf = dest;
++ int count;
+
+ /*
+ * The first byte of the packet we send to the device contains an
+@@ -317,8 +318,9 @@ static int ir_prepare_write_buffer(struc
+ */
+ *buf = ir_xbof | ir_baud;
+
+- return kfifo_out_locked(&port->write_fifo, buf + 1, size - 1,
++ count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1,
+ &port->lock);
++ return count + 1;
+ }
+
+ static void ir_process_read_urb(struct urb *urb)
diff --git a/usb/usb-kl5usb105-fix-memory-leak.patch b/usb/usb-kl5usb105-fix-memory-leak.patch
new file mode 100644
index 00000000000000..8611cdcdf38bda
--- /dev/null
+++ b/usb/usb-kl5usb105-fix-memory-leak.patch
@@ -0,0 +1,28 @@
+From jhovold@gmail.com Thu May 20 10:58:20 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:38 +0200
+Subject: USB: kl5usb105: fix memory leak
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>, stable <stable@kernel.org>
+Message-ID: <1274220101-13873-10-git-send-email-jhovold@gmail.com>
+
+
+Private data was not freed on error path in startup.
+
+Cc: stable <stable@kernel.org>
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/kl5kusb105.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -321,6 +321,7 @@ err_cleanup:
+ usb_free_urb(priv->write_urb_pool[j]);
+ }
+ }
++ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
diff --git a/usb/usb-kl5usb105-minor-clean-ups.patch b/usb/usb-kl5usb105-minor-clean-ups.patch
new file mode 100644
index 00000000000000..51e876e7c0202d
--- /dev/null
+++ b/usb/usb-kl5usb105-minor-clean-ups.patch
@@ -0,0 +1,228 @@
+From jhovold@gmail.com Thu May 20 10:58:29 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:39 +0200
+Subject: USB: kl5usb105: minor clean ups
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-11-git-send-email-jhovold@gmail.com>
+
+
+Whitespace changes and some removed comments.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/kl5kusb105.c | 79 ++++++++++++++++------------------------
+ 1 file changed, 33 insertions(+), 46 deletions(-)
+
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -107,7 +107,7 @@ static struct usb_driver kl5kusb105d_dri
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+- .no_dynamic_id = 1,
++ .no_dynamic_id = 1,
+ };
+
+ static struct usb_serial_driver kl5kusb105d_device = {
+@@ -115,26 +115,26 @@ static struct usb_serial_driver kl5kusb1
+ .owner = THIS_MODULE,
+ .name = "kl5kusb105d",
+ },
+- .description = "KL5KUSB105D / PalmConnect",
+- .usb_driver = &kl5kusb105d_driver,
+- .id_table = id_table,
+- .num_ports = 1,
+- .open = klsi_105_open,
+- .close = klsi_105_close,
+- .write = klsi_105_write,
+- .write_bulk_callback = klsi_105_write_bulk_callback,
+- .chars_in_buffer = klsi_105_chars_in_buffer,
+- .write_room = klsi_105_write_room,
+- .read_bulk_callback = klsi_105_read_bulk_callback,
+- .set_termios = klsi_105_set_termios,
+- /*.break_ctl = klsi_105_break_ctl,*/
+- .tiocmget = klsi_105_tiocmget,
+- .tiocmset = klsi_105_tiocmset,
+- .attach = klsi_105_startup,
+- .disconnect = klsi_105_disconnect,
+- .release = klsi_105_release,
+- .throttle = klsi_105_throttle,
+- .unthrottle = klsi_105_unthrottle,
++ .description = "KL5KUSB105D / PalmConnect",
++ .usb_driver = &kl5kusb105d_driver,
++ .id_table = id_table,
++ .num_ports = 1,
++ .open = klsi_105_open,
++ .close = klsi_105_close,
++ .write = klsi_105_write,
++ .write_bulk_callback = klsi_105_write_bulk_callback,
++ .chars_in_buffer = klsi_105_chars_in_buffer,
++ .write_room = klsi_105_write_room,
++ .read_bulk_callback = klsi_105_read_bulk_callback,
++ .set_termios = klsi_105_set_termios,
++ /*.break_ctl = klsi_105_break_ctl,*/
++ .tiocmget = klsi_105_tiocmget,
++ .tiocmset = klsi_105_tiocmset,
++ .attach = klsi_105_startup,
++ .disconnect = klsi_105_disconnect,
++ .release = klsi_105_release,
++ .throttle = klsi_105_throttle,
++ .unthrottle = klsi_105_unthrottle,
+ };
+
+ struct klsi_105_port_settings {
+@@ -189,7 +189,7 @@ static int klsi_105_chg_port_settings(st
+ settings->pktlen, settings->baudrate, settings->databits,
+ settings->unknown1, settings->unknown2);
+ return rc;
+-} /* klsi_105_chg_port_settings */
++}
+
+ /* translate a 16-bit status value from the device to linux's TIO bits */
+ static unsigned long klsi_105_status2linestate(const __u16 status)
+@@ -202,6 +202,7 @@ static unsigned long klsi_105_status2lin
+
+ return res;
+ }
++
+ /*
+ * Read line control via vendor command and return result through
+ * *line_state_p
+@@ -325,8 +326,7 @@ err_cleanup:
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
+-} /* klsi_105_startup */
+-
++}
+
+ static void klsi_105_disconnect(struct usb_serial *serial)
+ {
+@@ -352,8 +352,7 @@ static void klsi_105_disconnect(struct u
+ }
+ }
+ }
+-} /* klsi_105_disconnect */
+-
++}
+
+ static void klsi_105_release(struct usb_serial *serial)
+ {
+@@ -367,7 +366,7 @@ static void klsi_105_release(struct usb_
+
+ kfree(priv);
+ }
+-} /* klsi_105_release */
++}
+
+ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
+ {
+@@ -461,8 +460,7 @@ static int klsi_105_open(struct tty_str
+ exit:
+ kfree(cfg);
+ return retval;
+-} /* klsi_105_open */
+-
++}
+
+ static void klsi_105_close(struct usb_serial_port *port)
+ {
+@@ -498,8 +496,7 @@ static void klsi_105_close(struct usb_se
+ dev_info(&port->serial->dev->dev,
+ "port stats: %ld bytes in, %ld bytes out\n",
+ priv->bytes_in, priv->bytes_out);
+-} /* klsi_105_close */
+-
++}
+
+ /* We need to write a complete 64-byte data block and encode the
+ * number actually sent in the first double-byte, LSB-order. That
+@@ -507,7 +504,6 @@ static void klsi_105_close(struct usb_se
+ */
+ #define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */
+
+-
+ static int klsi_105_write(struct tty_struct *tty,
+ struct usb_serial_port *port, const unsigned char *buf, int count)
+ {
+@@ -586,7 +582,7 @@ exit:
+ priv->bytes_out += bytes_sent;
+
+ return bytes_sent; /* that's how much we wrote */
+-} /* klsi_105_write */
++}
+
+ static void klsi_105_write_bulk_callback(struct urb *urb)
+ {
+@@ -602,8 +598,7 @@ static void klsi_105_write_bulk_callback
+ }
+
+ usb_serial_port_softint(port);
+-} /* klsi_105_write_bulk_completion_callback */
+-
++}
+
+ /* return number of characters currently in the writing process */
+ static int klsi_105_chars_in_buffer(struct tty_struct *tty)
+@@ -647,8 +642,6 @@ static int klsi_105_write_room(struct tt
+ return room;
+ }
+
+-
+-
+ static void klsi_105_read_bulk_callback(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
+@@ -720,8 +713,7 @@ static void klsi_105_read_bulk_callback(
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, rc);
+-} /* klsi_105_read_bulk_callback */
+-
++}
+
+ static void klsi_105_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+@@ -888,8 +880,7 @@ static void klsi_105_set_termios(struct
+ klsi_105_chg_port_settings(port, cfg);
+ err:
+ kfree(cfg);
+-} /* klsi_105_set_termios */
+-
++}
+
+ #if 0
+ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
+@@ -907,7 +898,7 @@ static void mct_u232_break_ctl(struct tt
+ lcr |= MCT_U232_SET_BREAK;
+
+ mct_u232_set_line_ctrl(serial, lcr);
+-} /* mct_u232_break_ctl */
++}
+ #endif
+
+ static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file)
+@@ -986,7 +977,6 @@ static void klsi_105_unthrottle(struct t
+ }
+
+
+-
+ static int __init klsi_105_init(void)
+ {
+ int retval;
+@@ -1006,7 +996,6 @@ failed_usb_serial_register:
+ return retval;
+ }
+
+-
+ static void __exit klsi_105_exit(void)
+ {
+ usb_deregister(&kl5kusb105d_driver);
+@@ -1024,5 +1013,3 @@ MODULE_LICENSE("GPL");
+
+ module_param(debug, bool, S_IRUGO | S_IWUSR);
+ MODULE_PARM_DESC(debug, "enable extensive debugging messages");
+-
+-/* vim: set sts=8 ts=8 sw=8: */
diff --git a/usb/usb-kl5usb105-reimplement-using-generic-framework.patch b/usb/usb-kl5usb105-reimplement-using-generic-framework.patch
new file mode 100644
index 00000000000000..ff3f9bc4a9a615
--- /dev/null
+++ b/usb/usb-kl5usb105-reimplement-using-generic-framework.patch
@@ -0,0 +1,556 @@
+From jhovold@gmail.com Thu May 20 10:58:37 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:40 +0200
+Subject: USB: kl5usb105: reimplement using generic framework
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-12-git-send-email-jhovold@gmail.com>
+
+
+Kill custom read and write implementations (static per-port,
+singleton(!) urb pool).
+
+Also remove changelog header (can be retrieved through git).
+
+Read processing and write-buffer handling tested using a cp210x device
+in a loopback setup.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/kl5kusb105.c | 380 ++++------------------------------------
+ 1 file changed, 47 insertions(+), 333 deletions(-)
+
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -1,6 +1,7 @@
+ /*
+ * KLSI KL5KUSB105 chip RS232 converter driver
+ *
++ * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
+ * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+@@ -34,17 +35,6 @@
+ * implement handshaking or decide that we do not support it
+ */
+
+-/* History:
+- * 0.3a - implemented pools of write URBs
+- * 0.3 - alpha version for public testing
+- * 0.2 - TIOCMGET works, so autopilot(1) can be used!
+- * 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l
+- *
+- * The driver skeleton is mainly based on mct_u232.c and various other
+- * pieces of code shamelessly copied from the drivers/usb/serial/ directory.
+- */
+-
+-
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+@@ -64,8 +54,8 @@ static int debug;
+ /*
+ * Version Information
+ */
+-#define DRIVER_VERSION "v0.3a"
+-#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
++#define DRIVER_VERSION "v0.4"
++#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
+ #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
+
+
+@@ -73,23 +63,17 @@ static int debug;
+ * Function prototypes
+ */
+ static int klsi_105_startup(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);
+ static void klsi_105_close(struct usb_serial_port *port);
+-static int klsi_105_write(struct tty_struct *tty,
+- struct usb_serial_port *port, const unsigned char *buf, int count);
+-static void klsi_105_write_bulk_callback(struct urb *urb);
+-static int klsi_105_chars_in_buffer(struct tty_struct *tty);
+-static int klsi_105_write_room(struct tty_struct *tty);
+-static void klsi_105_read_bulk_callback(struct urb *urb);
+ static void klsi_105_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old);
+-static void klsi_105_throttle(struct tty_struct *tty);
+-static void klsi_105_unthrottle(struct tty_struct *tty);
+ static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file);
+ static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
++static void klsi_105_process_read_urb(struct urb *urb);
++static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
++ void *dest, size_t size);
+
+ /*
+ * All of the device info needed for the KLSI converters.
+@@ -119,22 +103,19 @@ static struct usb_serial_driver kl5kusb1
+ .usb_driver = &kl5kusb105d_driver,
+ .id_table = id_table,
+ .num_ports = 1,
++ .bulk_out_size = 64,
+ .open = klsi_105_open,
+ .close = klsi_105_close,
+- .write = klsi_105_write,
+- .write_bulk_callback = klsi_105_write_bulk_callback,
+- .chars_in_buffer = klsi_105_chars_in_buffer,
+- .write_room = klsi_105_write_room,
+- .read_bulk_callback = klsi_105_read_bulk_callback,
+ .set_termios = klsi_105_set_termios,
+ /*.break_ctl = klsi_105_break_ctl,*/
+ .tiocmget = klsi_105_tiocmget,
+ .tiocmset = klsi_105_tiocmset,
+ .attach = klsi_105_startup,
+- .disconnect = klsi_105_disconnect,
+ .release = klsi_105_release,
+- .throttle = klsi_105_throttle,
+- .unthrottle = klsi_105_unthrottle,
++ .throttle = usb_serial_generic_throttle,
++ .unthrottle = usb_serial_generic_unthrottle,
++ .process_read_urb = klsi_105_process_read_urb,
++ .prepare_write_buffer = klsi_105_prepare_write_buffer,
+ };
+
+ struct klsi_105_port_settings {
+@@ -145,18 +126,11 @@ struct klsi_105_port_settings {
+ __u8 unknown2;
+ } __attribute__ ((packed));
+
+-/* we implement a pool of NUM_URBS urbs per usb_serial */
+-#define NUM_URBS 1
+-#define URB_TRANSFER_BUFFER_SIZE 64
+ struct klsi_105_private {
+ struct klsi_105_port_settings cfg;
+ struct ktermios termios;
+ unsigned long line_state; /* modem line settings */
+- /* write pool */
+- struct urb *write_urb_pool[NUM_URBS];
+ spinlock_t lock;
+- unsigned long bytes_in;
+- unsigned long bytes_out;
+ };
+
+
+@@ -259,7 +233,7 @@ static int klsi_105_get_line_state(struc
+ static int klsi_105_startup(struct usb_serial *serial)
+ {
+ struct klsi_105_private *priv;
+- int i, j;
++ int i;
+
+ /* check if we support the product id (see keyspan.c)
+ * FIXME
+@@ -283,29 +257,9 @@ static int klsi_105_startup(struct usb_s
+
+ priv->line_state = 0;
+
+- priv->bytes_in = 0;
+- priv->bytes_out = 0;
+ usb_set_serial_port_data(serial->port[i], priv);
+
+ spin_lock_init(&priv->lock);
+- for (j = 0; j < NUM_URBS; j++) {
+- struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+-
+- priv->write_urb_pool[j] = urb;
+- if (urb == NULL) {
+- dev_err(&serial->dev->dev, "No more urbs???\n");
+- goto err_cleanup;
+- }
+-
+- urb->transfer_buffer =
+- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+- if (!urb->transfer_buffer) {
+- dev_err(&serial->dev->dev,
+- "%s - out of memory for urb buffers.\n",
+- __func__);
+- goto err_cleanup;
+- }
+- }
+
+ /* priv->termios is left uninitalized until port opening */
+ init_waitqueue_head(&serial->port[i]->write_wait);
+@@ -316,56 +270,20 @@ static int klsi_105_startup(struct usb_s
+ err_cleanup:
+ for (; i >= 0; i--) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+- for (j = 0; j < NUM_URBS; j++) {
+- if (priv->write_urb_pool[j]) {
+- kfree(priv->write_urb_pool[j]->transfer_buffer);
+- usb_free_urb(priv->write_urb_pool[j]);
+- }
+- }
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
+ }
+
+-static void klsi_105_disconnect(struct usb_serial *serial)
+-{
+- int i;
+-
+- dbg("%s", __func__);
+-
+- /* stop reads and writes on all ports */
+- for (i = 0; i < serial->num_ports; ++i) {
+- struct klsi_105_private *priv =
+- usb_get_serial_port_data(serial->port[i]);
+-
+- if (priv) {
+- /* kill our write urb pool */
+- int j;
+- struct urb **write_urbs = priv->write_urb_pool;
+-
+- for (j = 0; j < NUM_URBS; j++) {
+- if (write_urbs[j]) {
+- usb_kill_urb(write_urbs[j]);
+- usb_free_urb(write_urbs[j]);
+- }
+- }
+- }
+- }
+-}
+-
+ 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);
+- }
++ for (i = 0; i < serial->num_ports; ++i)
++ kfree(usb_get_serial_port_data(serial->port[i]));
+ }
+
+ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
+@@ -416,18 +334,8 @@ static int klsi_105_open(struct tty_str
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* READ_ON and urb submission */
+- 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,
+- klsi_105_read_bulk_callback,
+- port);
+-
+- rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
++ rc = usb_serial_generic_open(tty, port);
+ if (rc) {
+- dev_err(&port->dev, "%s - failed submitting read urb, "
+- "error %d\n", __func__, rc);
+ retval = rc;
+ goto exit;
+ }
+@@ -464,7 +372,6 @@ exit:
+
+ static void klsi_105_close(struct usb_serial_port *port)
+ {
+- struct klsi_105_private *priv = usb_get_serial_port_data(port);
+ int rc;
+
+ dbg("%s port %d", __func__, port->number);
+@@ -487,232 +394,61 @@ static void klsi_105_close(struct usb_se
+ mutex_unlock(&port->serial->disc_mutex);
+
+ /* shutdown our bulk reads and writes */
+- usb_kill_urb(port->write_urb);
+- usb_kill_urb(port->read_urb);
+- /* unlink our write pool */
+- /* FIXME */
++ usb_serial_generic_close(port);
++
+ /* wgg - do I need this? I think so. */
+ usb_kill_urb(port->interrupt_in_urb);
+- dev_info(&port->serial->dev->dev,
+- "port stats: %ld bytes in, %ld bytes out\n",
+- priv->bytes_in, priv->bytes_out);
+ }
+
+ /* We need to write a complete 64-byte data block and encode the
+ * number actually sent in the first double-byte, LSB-order. That
+ * leaves at most 62 bytes of payload.
+ */
+-#define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */
+-
+-static int klsi_105_write(struct tty_struct *tty,
+- struct usb_serial_port *port, const unsigned char *buf, int count)
+-{
+- struct klsi_105_private *priv = usb_get_serial_port_data(port);
+- int result, size;
+- int bytes_sent = 0;
+-
+- dbg("%s - port %d", __func__, port->number);
+-
+- while (count > 0) {
+- /* try to find a free urb (write 0 bytes if none) */
+- struct urb *urb = NULL;
+- unsigned long flags;
+- int i;
+- /* since the pool is per-port we might not need
+- the spin lock !? */
+- spin_lock_irqsave(&priv->lock, flags);
+- for (i = 0; i < NUM_URBS; i++) {
+- if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+- urb = priv->write_urb_pool[i];
+- dbg("%s - using pool URB %d", __func__, i);
+- break;
+- }
+- }
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- if (urb == NULL) {
+- dbg("%s - no more free urbs", __func__);
+- goto exit;
+- }
+-
+- if (urb->transfer_buffer == NULL) {
+- urb->transfer_buffer =
+- kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
+- if (urb->transfer_buffer == NULL) {
+- dev_err(&port->dev,
+- "%s - no more kernel memory...\n",
+- __func__);
+- goto exit;
+- }
+- }
+-
+- size = min(count, port->bulk_out_size - KLSI_105_DATA_OFFSET);
+- size = min(size, URB_TRANSFER_BUFFER_SIZE -
+- KLSI_105_DATA_OFFSET);
+-
+- memcpy(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size);
+-
+- /* write payload size into transfer buffer */
+- ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF);
+- ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8);
+-
+- /* set up our urb */
+- usb_fill_bulk_urb(urb, port->serial->dev,
+- usb_sndbulkpipe(port->serial->dev,
+- port->bulk_out_endpointAddress),
+- urb->transfer_buffer,
+- URB_TRANSFER_BUFFER_SIZE,
+- klsi_105_write_bulk_callback,
+- port);
+-
+- /* send the data out the bulk port */
+- result = usb_submit_urb(urb, GFP_ATOMIC);
+- if (result) {
+- dev_err(&port->dev,
+- "%s - failed submitting write urb, error %d\n",
+- __func__, result);
+- goto exit;
+- }
+- buf += size;
+- bytes_sent += size;
+- count -= size;
+- }
+-exit:
+- /* lockless, but it's for debug info only... */
+- priv->bytes_out += bytes_sent;
+-
+- return bytes_sent; /* that's how much we wrote */
+-}
+-
+-static void klsi_105_write_bulk_callback(struct urb *urb)
+-{
+- struct usb_serial_port *port = urb->context;
+- int status = urb->status;
+-
+- dbg("%s - port %d", __func__, port->number);
+-
+- if (status) {
+- dbg("%s - nonzero write bulk status received: %d", __func__,
+- status);
+- return;
+- }
+-
+- usb_serial_port_softint(port);
+-}
+-
+-/* return number of characters currently in the writing process */
+-static int klsi_105_chars_in_buffer(struct tty_struct *tty)
++#define KLSI_HDR_LEN 2
++static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
++ void *dest, size_t size)
+ {
+- struct usb_serial_port *port = tty->driver_data;
+- int chars = 0;
+- int i;
+- unsigned long flags;
+- struct klsi_105_private *priv = usb_get_serial_port_data(port);
+-
+- spin_lock_irqsave(&priv->lock, flags);
++ unsigned char *buf = dest;
++ int count;
+
+- for (i = 0; i < NUM_URBS; ++i) {
+- if (priv->write_urb_pool[i]->status == -EINPROGRESS)
+- chars += URB_TRANSFER_BUFFER_SIZE;
+- }
+-
+- spin_unlock_irqrestore(&priv->lock, flags);
++ count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
++ &port->lock);
++ put_unaligned_le16(count, buf);
+
+- dbg("%s - returns %d", __func__, chars);
+- return chars;
++ return count + KLSI_HDR_LEN;
+ }
+
+-static int klsi_105_write_room(struct tty_struct *tty)
+-{
+- struct usb_serial_port *port = tty->driver_data;
+- unsigned long flags;
+- int i;
+- int room = 0;
+- struct klsi_105_private *priv = usb_get_serial_port_data(port);
+-
+- spin_lock_irqsave(&priv->lock, flags);
+- for (i = 0; i < NUM_URBS; ++i) {
+- if (priv->write_urb_pool[i]->status != -EINPROGRESS)
+- room += URB_TRANSFER_BUFFER_SIZE;
+- }
+-
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- dbg("%s - returns %d", __func__, room);
+- return room;
+-}
+-
+-static void klsi_105_read_bulk_callback(struct urb *urb)
++/* The data received is preceded by a length double-byte in LSB-first order.
++ */
++static void klsi_105_process_read_urb(struct urb *urb)
+ {
+ struct usb_serial_port *port = urb->context;
+- struct klsi_105_private *priv = usb_get_serial_port_data(port);
+- struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+- int rc;
+- int status = urb->status;
++ struct tty_struct *tty;
++ unsigned len;
+
+- dbg("%s - port %d", __func__, port->number);
++ /* empty urbs seem to happen, we ignore them */
++ if (!urb->actual_length)
++ return;
+
+- /* The urb might have been killed. */
+- if (status) {
+- dbg("%s - nonzero read bulk status received: %d", __func__,
+- status);
++ if (urb->actual_length <= KLSI_HDR_LEN) {
++ dbg("%s - malformed packet", __func__);
+ return;
+ }
+
+- /* The data received is again preceded by a length double-byte in LSB-
+- * first order (see klsi_105_write() )
+- */
+- if (urb->actual_length == 0) {
+- /* empty urbs seem to happen, we ignore them */
+- /* dbg("%s - emtpy URB", __func__); */
+- ;
+- } else if (urb->actual_length <= 2) {
+- dbg("%s - size %d URB not understood", __func__,
+- urb->actual_length);
+- usb_serial_debug_data(debug, &port->dev, __func__,
+- urb->actual_length, data);
+- } else {
+- int bytes_sent = ((__u8 *) data)[0] +
+- ((unsigned int) ((__u8 *) data)[1] << 8);
+- tty = tty_port_tty_get(&port->port);
+- /* we should immediately resubmit the URB, before attempting
+- * to pass the data on to the tty layer. But that needs locking
+- * against re-entry an then mixed-up data because of
+- * intermixed tty_flip_buffer_push()s
+- * FIXME
+- */
+- usb_serial_debug_data(debug, &port->dev, __func__,
+- urb->actual_length, data);
++ tty = tty_port_tty_get(&port->port);
++ if (!tty)
++ return;
+
+- if (bytes_sent + 2 > urb->actual_length) {
+- dbg("%s - trying to read more data than available"
+- " (%d vs. %d)", __func__,
+- bytes_sent+2, urb->actual_length);
+- /* cap at implied limit */
+- bytes_sent = urb->actual_length - 2;
+- }
++ len = get_unaligned_le16(data);
++ if (len > urb->actual_length - KLSI_HDR_LEN) {
++ dbg("%s - packet length mismatch", __func__);
++ len = urb->actual_length - KLSI_HDR_LEN;
++ }
+
+- tty_insert_flip_string(tty, data + 2, bytes_sent);
+- tty_flip_buffer_push(tty);
+- tty_kref_put(tty);
+-
+- /* again lockless, but debug info only */
+- priv->bytes_in += bytes_sent;
+- }
+- /* 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,
+- klsi_105_read_bulk_callback,
+- port);
+- rc = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+- if (rc)
+- dev_err(&port->dev,
+- "%s - failed resubmitting read urb, error %d\n",
+- __func__, rc);
++ tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len);
++ tty_flip_buffer_push(tty);
++ tty_kref_put(tty);
+ }
+
+ static void klsi_105_set_termios(struct tty_struct *tty,
+@@ -954,28 +690,6 @@ static int klsi_105_tiocmset(struct tty_
+ return retval;
+ }
+
+-static void klsi_105_throttle(struct tty_struct *tty)
+-{
+- struct usb_serial_port *port = tty->driver_data;
+- dbg("%s - port %d", __func__, port->number);
+- usb_kill_urb(port->read_urb);
+-}
+-
+-static void klsi_105_unthrottle(struct tty_struct *tty)
+-{
+- struct usb_serial_port *port = tty->driver_data;
+- int result;
+-
+- dbg("%s - port %d", __func__, port->number);
+-
+- port->read_urb->dev = port->serial->dev;
+- 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);
+-}
+-
+
+ static int __init klsi_105_init(void)
+ {
diff --git a/usb/usb-musb-update-gfp-slab.h-includes.patch b/usb/usb-musb-update-gfp-slab.h-includes.patch
new file mode 100644
index 00000000000000..03df19d39384b3
--- /dev/null
+++ b/usb/usb-musb-update-gfp-slab.h-includes.patch
@@ -0,0 +1,29 @@
+From sfr@canb.auug.org.au Thu May 20 10:59:27 2010
+From: Tejun Heo <tj@kernel.org>
+Date: Thu, 20 May 2010 01:44:20 +1000
+Subject: usb: musb: update gfp/slab.h includes
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-next@vger.kernel.org, linux-kernel@vger.kernel.org, Tejun Heo <tj@kernel.org>
+Message-ID: <20100520014420.22a0e715.sfr@canb.auug.org.au>
+
+Implicit slab.h inclusion via percpu.h is about to go away. Make sure
+gfp.h or slab.h is included as necessary.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Cc: Stephen Rothwell <sfr@canb.auug.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_debugfs.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/usb/musb/musb_debugfs.c
++++ b/drivers/usb/musb/musb_debugfs.c
+@@ -34,7 +34,6 @@
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+-#include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/kobject.h>
diff --git a/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch b/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch
new file mode 100644
index 00000000000000..4aad8f00a97e54
--- /dev/null
+++ b/usb/usb-safe_serial-reimplement-read-using-generic-framework.patch
@@ -0,0 +1,97 @@
+From jhovold@gmail.com Thu May 20 10:57:01 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:31 +0200
+Subject: USB: safe_serial: reimplement read using generic framework
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-3-git-send-email-jhovold@gmail.com>
+
+
+Use process_read_urb to implement read processing.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/safe_serial.c | 47 ++++++---------------------------------
+ 1 file changed, 8 insertions(+), 39 deletions(-)
+
+--- a/drivers/usb/serial/safe_serial.c
++++ b/drivers/usb/serial/safe_serial.c
+@@ -213,38 +213,20 @@ static __u16 __inline__ fcs_compute10(un
+ return fcs;
+ }
+
+-static void safe_read_bulk_callback(struct urb *urb)
++static void safe_process_read_urb(struct urb *urb)
+ {
+- struct usb_serial_port *port = urb->context;
++ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ unsigned char length = urb->actual_length;
+ struct tty_struct *tty;
+- int result;
+- int status = urb->status;
+
+- dbg("%s", __func__);
+-
+- if (status) {
+- dbg("%s - nonzero read bulk status received: %d",
+- __func__, status);
++ if (!length)
+ return;
+- }
+
+- dbg("safe_read_bulk_callback length: %d",
+- port->read_urb->actual_length);
+-#ifdef ECHO_RCV
+- {
+- int i;
+- unsigned char *cp = port->read_urb->transfer_buffer;
+- for (i = 0; i < port->read_urb->actual_length; i++) {
+- if ((i % 32) == 0)
+- printk("\nru[%02x] ", i);
+- printk("%02x ", *cp++);
+- }
+- printk("\n");
+- }
+-#endif
+ tty = tty_port_tty_get(&port->port);
++ if (!tty)
++ return;
++
+ if (safe) {
+ __u16 fcs;
+ fcs = fcs_compute10(data, length, CRC10_INITFCS);
+@@ -268,21 +250,8 @@ static void safe_read_bulk_callback(stru
+ tty_insert_flip_string(tty, data, length);
+ tty_flip_buffer_push(tty);
+ }
+- tty_kref_put(tty);
+
+- /* Continue trying to always read */
+- usb_fill_bulk_urb(urb, port->serial->dev,
+- usb_rcvbulkpipe(port->serial->dev,
+- port->bulk_in_endpointAddress),
+- urb->transfer_buffer, urb->transfer_buffer_length,
+- safe_read_bulk_callback, port);
+-
+- result = usb_submit_urb(urb, GFP_ATOMIC);
+- if (result)
+- dev_err(&port->dev,
+- "%s - failed resubmitting read urb, error %d\n",
+- __func__, result);
+- /* FIXME: Need a mechanism to retry later if this happens */
++ tty_kref_put(tty);
+ }
+
+ static int safe_prepare_write_buffer(struct usb_serial_port *port,
+@@ -343,7 +312,7 @@ static struct usb_serial_driver safe_dev
+ .id_table = id_table,
+ .usb_driver = &safe_driver,
+ .num_ports = 1,
+- .read_bulk_callback = safe_read_bulk_callback,
++ .process_read_urb = safe_process_read_urb,
+ .prepare_write_buffer = safe_prepare_write_buffer,
+ .attach = safe_startup,
+ };
diff --git a/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch b/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch
new file mode 100644
index 00000000000000..a2f927462f9a85
--- /dev/null
+++ b/usb/usb-safe_serial-reimplement-write-using-generic-framework.patch
@@ -0,0 +1,204 @@
+From jhovold@gmail.com Thu May 20 10:56:47 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:30 +0200
+Subject: USB: safe_serial: reimplement write using generic framework
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-2-git-send-email-jhovold@gmail.com>
+
+
+Kill custom single-urb write implementation.
+
+Note that this driver still depended on the write callback from the old
+generic framework.
+
+Tested against original read processing using a cp210x device in a
+loopback setup.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/safe_serial.c | 143 ++++++++-------------------------------
+ 1 file changed, 32 insertions(+), 111 deletions(-)
+
+--- a/drivers/usb/serial/safe_serial.c
++++ b/drivers/usb/serial/safe_serial.c
+@@ -1,6 +1,7 @@
+ /*
+ * Safe Encapsulated USB Serial Driver
+ *
++ * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
+ * Copyright (C) 2001 Lineo
+ * Copyright (C) 2001 Hewlett-Packard
+ *
+@@ -84,8 +85,8 @@ static int debug;
+ static int safe = 1;
+ static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
+
+-#define DRIVER_VERSION "v0.0b"
+-#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
++#define DRIVER_VERSION "v0.1"
++#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>"
+ #define DRIVER_DESC "USB Safe Encapsulated Serial"
+
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+@@ -284,119 +285,40 @@ static void safe_read_bulk_callback(stru
+ /* FIXME: Need a mechanism to retry later if this happens */
+ }
+
+-static int safe_write(struct tty_struct *tty, struct usb_serial_port *port,
+- const unsigned char *buf, int count)
++static int safe_prepare_write_buffer(struct usb_serial_port *port,
++ void *dest, size_t size)
+ {
+- unsigned char *data;
+- int result;
+- int i;
+- int packet_length;
+-
+- dbg("safe_write port: %p %d urb: %p count: %d",
+- port, port->number, port->write_urb, count);
+-
+- if (!port->write_urb) {
+- dbg("%s - write urb NULL", __func__);
+- return 0;
+- }
+-
+- dbg("safe_write write_urb: %d transfer_buffer_length",
+- port->write_urb->transfer_buffer_length);
+-
+- if (!port->write_urb->transfer_buffer_length) {
+- dbg("%s - write urb transfer_buffer_length zero", __func__);
+- return 0;
+- }
+- if (count == 0) {
+- dbg("%s - write request of 0 bytes", __func__);
+- return 0;
+- }
+- spin_lock_bh(&port->lock);
+- if (port->write_urb_busy) {
+- spin_unlock_bh(&port->lock);
+- dbg("%s - already writing", __func__);
+- return 0;
+- }
+- port->write_urb_busy = 1;
+- spin_unlock_bh(&port->lock);
+-
+- packet_length = port->bulk_out_size; /* get max packetsize */
+-
+- i = packet_length - (safe ? 2 : 0); /* get bytes to send */
+- count = (count > i) ? i : count;
+-
+-
+- /* get the data into the transfer buffer */
+- data = port->write_urb->transfer_buffer;
+- memset(data, '0', packet_length);
+-
+- memcpy(data, buf, count);
+-
+- if (safe) {
+- __u16 fcs;
+-
+- /* pad if necessary */
+- if (!padded)
+- packet_length = count + 2;
+- /* set count */
+- data[packet_length - 2] = count << 2;
+- data[packet_length - 1] = 0;
+-
+- /* compute fcs and insert into trailer */
+- fcs = fcs_compute10(data, packet_length, CRC10_INITFCS);
+- data[packet_length - 2] |= fcs >> 8;
+- data[packet_length - 1] |= fcs & 0xff;
+-
+- /* set length to send */
+- port->write_urb->transfer_buffer_length = packet_length;
++ unsigned char *buf = dest;
++ int count;
++ int trailer_len;
++ int pkt_len;
++ __u16 fcs;
++
++ trailer_len = safe ? 2 : 0;
++
++ count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len,
++ &port->lock);
++ if (!safe)
++ return count;
++
++ /* pad if necessary */
++ if (padded) {
++ pkt_len = size;
++ memset(buf + count, '0', pkt_len - count - trailer_len);
+ } else {
+- port->write_urb->transfer_buffer_length = count;
++ pkt_len = count + trailer_len;
+ }
+
+- usb_serial_debug_data(debug, &port->dev, __func__, count,
+- port->write_urb->transfer_buffer);
+-#ifdef ECHO_TX
+- {
+- int i;
+- unsigned char *cp = port->write_urb->transfer_buffer;
+- for (i = 0; i < port->write_urb->transfer_buffer_length; i++) {
+- if ((i % 32) == 0)
+- printk("\nsu[%02x] ", i);
+- printk("%02x ", *cp++);
+- }
+- printk("\n");
+- }
+-#endif
+- port->write_urb->dev = port->serial->dev;
+- result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+- if (result) {
+- port->write_urb_busy = 0;
+- dev_err(&port->dev,
+- "%s - failed submitting write urb, error %d\n",
+- __func__, result);
+- return 0;
+- }
+- dbg("%s urb: %p submitted", __func__, port->write_urb);
+-
+- return count;
+-}
+-
+-static int safe_write_room(struct tty_struct *tty)
+-{
+- struct usb_serial_port *port = tty->driver_data;
+- int room = 0; /* Default: no room */
+- unsigned long flags;
++ /* set count */
++ buf[pkt_len - 2] = count << 2;
++ buf[pkt_len - 1] = 0;
+
+- dbg("%s", __func__);
++ /* compute fcs and insert into trailer */
++ fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS);
++ buf[pkt_len - 2] |= fcs >> 8;
++ buf[pkt_len - 1] |= fcs & 0xff;
+
+- spin_lock_irqsave(&port->lock, flags);
+- if (port->write_urb_busy)
+- room = port->bulk_out_size - (safe ? 2 : 0);
+- spin_unlock_irqrestore(&port->lock, flags);
+-
+- if (room)
+- dbg("safe_write_room returns %d", room);
+- return room;
++ return pkt_len;
+ }
+
+ static int safe_startup(struct usb_serial *serial)
+@@ -421,9 +343,8 @@ static struct usb_serial_driver safe_dev
+ .id_table = id_table,
+ .usb_driver = &safe_driver,
+ .num_ports = 1,
+- .write = safe_write,
+- .write_room = safe_write_room,
+ .read_bulk_callback = safe_read_bulk_callback,
++ .prepare_write_buffer = safe_prepare_write_buffer,
+ .attach = safe_startup,
+ };
+
diff --git a/usb/usb-safe_serial-straighten-out-read-processing.patch b/usb/usb-safe_serial-straighten-out-read-processing.patch
new file mode 100644
index 00000000000000..80bcd6bc172bf9
--- /dev/null
+++ b/usb/usb-safe_serial-straighten-out-read-processing.patch
@@ -0,0 +1,82 @@
+From jhovold@gmail.com Thu May 20 10:57:10 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:32 +0200
+Subject: USB: safe_serial: straighten out read processing
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-4-git-send-email-jhovold@gmail.com>
+
+
+Clean up read processing logic.
+
+Tested using a cp210x device in a loopback setup.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/safe_serial.c | 43 +++++++++++++++++++--------------------
+ 1 file changed, 21 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/serial/safe_serial.c
++++ b/drivers/usb/serial/safe_serial.c
+@@ -218,7 +218,9 @@ static void safe_process_read_urb(struct
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ unsigned char length = urb->actual_length;
++ int actual_length;
+ struct tty_struct *tty;
++ __u16 fcs;
+
+ if (!length)
+ return;
+@@ -227,30 +229,27 @@ static void safe_process_read_urb(struct
+ if (!tty)
+ return;
+
+- if (safe) {
+- __u16 fcs;
+- fcs = fcs_compute10(data, length, CRC10_INITFCS);
+- if (!fcs) {
+- int actual_length = data[length - 2] >> 2;
+- if (actual_length <= (length - 2)) {
+- dev_info(&urb->dev->dev, "%s - actual: %d\n",
+- __func__, actual_length);
+- tty_insert_flip_string(tty,
+- data, actual_length);
+- tty_flip_buffer_push(tty);
+- } else {
+- dev_err(&port->dev,
+- "%s - inconsistent lengths %d:%d\n",
+- __func__, actual_length, length);
+- }
+- } else {
+- dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
+- }
+- } else {
+- tty_insert_flip_string(tty, data, length);
+- tty_flip_buffer_push(tty);
++ if (!safe)
++ goto out;
++
++ fcs = fcs_compute10(data, length, CRC10_INITFCS);
++ if (fcs) {
++ dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
++ goto err;
+ }
+
++ actual_length = data[length - 2] >> 2;
++ if (actual_length > (length - 2)) {
++ dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n",
++ __func__, actual_length, length);
++ goto err;
++ }
++ dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length);
++ length = actual_length;
++out:
++ tty_insert_flip_string(tty, data, length);
++ tty_flip_buffer_push(tty);
++err:
+ tty_kref_put(tty);
+ }
+
diff --git a/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch b/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch
new file mode 100644
index 00000000000000..6a792b738ead11
--- /dev/null
+++ b/usb/usb-ti_usb-use-kfifo-to-implement-write-buffering.patch
@@ -0,0 +1,302 @@
+From jhovold@gmail.com Thu May 20 10:57:53 2010
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 19 May 2010 00:01:35 +0200
+Subject: USB: ti_usb: use kfifo to implement write buffering
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Johan Hovold <jhovold@gmail.com>
+Message-ID: <1274220101-13873-7-git-send-email-jhovold@gmail.com>
+
+
+Kill custom fifo implementation.
+
+Compile-only tested.
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/serial/ti_usb_3410_5052.c | 179 ++--------------------------------
+ 1 file changed, 14 insertions(+), 165 deletions(-)
+
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -30,7 +30,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/ioctl.h>
+ #include <linux/serial.h>
+-#include <linux/circ_buf.h>
++#include <linux/kfifo.h>
+ #include <linux/mutex.h>
+ #include <linux/uaccess.h>
+ #include <linux/usb.h>
+@@ -40,7 +40,7 @@
+
+ /* Defines */
+
+-#define TI_DRIVER_VERSION "v0.9"
++#define TI_DRIVER_VERSION "v0.10"
+ #define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>"
+ #define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver"
+
+@@ -82,7 +82,7 @@ struct ti_port {
+ spinlock_t tp_lock;
+ int tp_read_urb_state;
+ int tp_write_urb_in_use;
+- struct circ_buf *tp_write_buf;
++ struct kfifo write_fifo;
+ };
+
+ struct ti_device {
+@@ -144,15 +144,6 @@ static int ti_write_byte(struct ti_devic
+
+ static int ti_download_firmware(struct ti_device *tdev);
+
+-/* circular buffer */
+-static struct circ_buf *ti_buf_alloc(void);
+-static void ti_buf_free(struct circ_buf *cb);
+-static void ti_buf_clear(struct circ_buf *cb);
+-static int ti_buf_data_avail(struct circ_buf *cb);
+-static int ti_buf_space_avail(struct circ_buf *cb);
+-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count);
+-static int ti_buf_get(struct circ_buf *cb, char *buf, int count);
+-
+
+ /* Data */
+
+@@ -450,8 +441,8 @@ static int ti_startup(struct usb_serial
+ tport->tp_closing_wait = closing_wait;
+ init_waitqueue_head(&tport->tp_msr_wait);
+ init_waitqueue_head(&tport->tp_write_wait);
+- tport->tp_write_buf = ti_buf_alloc();
+- if (tport->tp_write_buf == NULL) {
++ if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
++ GFP_KERNEL)) {
+ dev_err(&dev->dev, "%s - out of memory\n", __func__);
+ kfree(tport);
+ status = -ENOMEM;
+@@ -468,7 +459,7 @@ static int ti_startup(struct usb_serial
+ free_tports:
+ for (--i; i >= 0; --i) {
+ tport = usb_get_serial_port_data(serial->port[i]);
+- ti_buf_free(tport->tp_write_buf);
++ kfifo_free(&tport->write_fifo);
+ kfree(tport);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+@@ -490,7 +481,7 @@ static void ti_release(struct usb_serial
+ for (i = 0; i < serial->num_ports; ++i) {
+ tport = usb_get_serial_port_data(serial->port[i]);
+ if (tport) {
+- ti_buf_free(tport->tp_write_buf);
++ kfifo_free(&tport->write_fifo);
+ kfree(tport);
+ }
+ }
+@@ -701,7 +692,6 @@ static int ti_write(struct tty_struct *t
+ const unsigned char *data, int count)
+ {
+ struct ti_port *tport = usb_get_serial_port_data(port);
+- unsigned long flags;
+
+ dbg("%s - port %d", __func__, port->number);
+
+@@ -713,10 +703,8 @@ static int ti_write(struct tty_struct *t
+ if (tport == NULL || !tport->tp_is_open)
+ return -ENODEV;
+
+- spin_lock_irqsave(&tport->tp_lock, flags);
+- count = ti_buf_put(tport->tp_write_buf, data, count);
+- spin_unlock_irqrestore(&tport->tp_lock, flags);
+-
++ count = kfifo_in_locked(&tport->write_fifo, data, count,
++ &tport->tp_lock);
+ ti_send(tport);
+
+ return count;
+@@ -736,7 +724,7 @@ static int ti_write_room(struct tty_stru
+ return 0;
+
+ spin_lock_irqsave(&tport->tp_lock, flags);
+- room = ti_buf_space_avail(tport->tp_write_buf);
++ room = kfifo_avail(&tport->write_fifo);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
+
+ dbg("%s - returns %d", __func__, room);
+@@ -757,7 +745,7 @@ static int ti_chars_in_buffer(struct tty
+ return 0;
+
+ spin_lock_irqsave(&tport->tp_lock, flags);
+- chars = ti_buf_data_avail(tport->tp_write_buf);
++ chars = kfifo_len(&tport->write_fifo);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
+
+ dbg("%s - returns %d", __func__, chars);
+@@ -1309,7 +1297,7 @@ static void ti_send(struct ti_port *tpor
+ if (tport->tp_write_urb_in_use)
+ goto unlock;
+
+- count = ti_buf_get(tport->tp_write_buf,
++ count = kfifo_out(&tport->write_fifo,
+ port->write_urb->transfer_buffer,
+ port->bulk_out_size);
+
+@@ -1504,7 +1492,7 @@ static void ti_drain(struct ti_port *tpo
+ add_wait_queue(&tport->tp_write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+- if (ti_buf_data_avail(tport->tp_write_buf) == 0
++ if (kfifo_len(&tport->write_fifo) == 0
+ || timeout == 0 || signal_pending(current)
+ || tdev->td_urb_error
+ || port->serial->disconnected) /* disconnect */
+@@ -1518,7 +1506,7 @@ static void ti_drain(struct ti_port *tpo
+
+ /* flush any remaining data in the buffer */
+ if (flush)
+- ti_buf_clear(tport->tp_write_buf);
++ kfifo_reset_out(&tport->write_fifo);
+
+ spin_unlock_irq(&tport->tp_lock);
+
+@@ -1761,142 +1749,3 @@ static int ti_download_firmware(struct t
+
+ return 0;
+ }
+-
+-
+-/* Circular Buffer Functions */
+-
+-/*
+- * ti_buf_alloc
+- *
+- * Allocate a circular buffer and all associated memory.
+- */
+-
+-static struct circ_buf *ti_buf_alloc(void)
+-{
+- struct circ_buf *cb;
+-
+- cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
+- if (cb == NULL)
+- return NULL;
+-
+- cb->buf = kmalloc(TI_WRITE_BUF_SIZE, GFP_KERNEL);
+- if (cb->buf == NULL) {
+- kfree(cb);
+- return NULL;
+- }
+-
+- ti_buf_clear(cb);
+-
+- return cb;
+-}
+-
+-
+-/*
+- * ti_buf_free
+- *
+- * Free the buffer and all associated memory.
+- */
+-
+-static void ti_buf_free(struct circ_buf *cb)
+-{
+- kfree(cb->buf);
+- kfree(cb);
+-}
+-
+-
+-/*
+- * ti_buf_clear
+- *
+- * Clear out all data in the circular buffer.
+- */
+-
+-static void ti_buf_clear(struct circ_buf *cb)
+-{
+- cb->head = cb->tail = 0;
+-}
+-
+-
+-/*
+- * ti_buf_data_avail
+- *
+- * Return the number of bytes of data available in the circular
+- * buffer.
+- */
+-
+-static int ti_buf_data_avail(struct circ_buf *cb)
+-{
+- return CIRC_CNT(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
+-}
+-
+-
+-/*
+- * ti_buf_space_avail
+- *
+- * Return the number of bytes of space available in the circular
+- * buffer.
+- */
+-
+-static int ti_buf_space_avail(struct circ_buf *cb)
+-{
+- return CIRC_SPACE(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
+-}
+-
+-
+-/*
+- * ti_buf_put
+- *
+- * Copy data data from a user buffer and put it into the circular buffer.
+- * Restrict to the amount of space available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count)
+-{
+- int c, ret = 0;
+-
+- while (1) {
+- c = CIRC_SPACE_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
+- if (count < c)
+- c = count;
+- if (c <= 0)
+- break;
+- memcpy(cb->buf + cb->head, buf, c);
+- cb->head = (cb->head + c) & (TI_WRITE_BUF_SIZE-1);
+- buf += c;
+- count -= c;
+- ret += c;
+- }
+-
+- return ret;
+-}
+-
+-
+-/*
+- * ti_buf_get
+- *
+- * Get data from the circular buffer and copy to the given buffer.
+- * Restrict to the amount of data available.
+- *
+- * Return the number of bytes copied.
+- */
+-
+-static int ti_buf_get(struct circ_buf *cb, char *buf, int count)
+-{
+- int c, ret = 0;
+-
+- while (1) {
+- c = CIRC_CNT_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
+- if (count < c)
+- c = count;
+- if (c <= 0)
+- break;
+- memcpy(buf, cb->buf + cb->tail, c);
+- cb->tail = (cb->tail + c) & (TI_WRITE_BUF_SIZE-1);
+- buf += c;
+- count -= c;
+- ret += c;
+- }
+-
+- return ret;
+-}
diff --git a/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch b/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch
index 7d371450313f57..1e8ffcb7b1c963 100644
--- a/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch
+++ b/usb/usb-xhci-correct-assumptions-about-number-of-rings-per-endpoint.patch
@@ -179,7 +179,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
SCT_FOR_CTX(SCT_PRI_TR) |
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -295,7 +295,8 @@ void xhci_ring_cmd_db(struct xhci_hcd *x
+@@ -312,7 +312,8 @@ void xhci_ring_cmd_db(struct xhci_hcd *x
static void ring_ep_doorbell(struct xhci_hcd *xhci,
unsigned int slot_id,
@@ -189,7 +189,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
{
struct xhci_virt_ep *ep;
unsigned int ep_state;
-@@ -314,7 +315,8 @@ static void ring_ep_doorbell(struct xhci
+@@ -331,7 +332,8 @@ static void ring_ep_doorbell(struct xhci
if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
&& !(ep_state & EP_HALTED)) {
field = xhci_readl(xhci, db_addr) & DB_MASK;
@@ -199,7 +199,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* Flush PCI posted writes - FIXME Matthew Wilcox says this
* isn't time-critical and we shouldn't make the CPU wait for
* the flush.
-@@ -323,6 +325,31 @@ static void ring_ep_doorbell(struct xhci
+@@ -340,6 +342,31 @@ static void ring_ep_doorbell(struct xhci
}
}
@@ -231,7 +231,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/*
* Find the segment that trb is in. Start searching in start_seg.
* If we must move past a segment that has a link TRB with a toggle cycle state
-@@ -365,14 +392,23 @@ static struct xhci_segment *find_trb_seg
+@@ -382,14 +409,23 @@ static struct xhci_segment *find_trb_seg
*/
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
@@ -257,7 +257,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
state->new_cycle_state = 0;
xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
state->new_deq_seg = find_trb_seg(cur_td->start_seg,
-@@ -452,11 +488,13 @@ static void td_to_noop(struct xhci_hcd *
+@@ -469,11 +505,13 @@ static void td_to_noop(struct xhci_hcd *
}
static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
@@ -272,7 +272,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
struct xhci_dequeue_state *deq_state)
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
-@@ -468,7 +506,7 @@ void xhci_queue_new_dequeue_state(struct
+@@ -485,7 +523,7 @@ void xhci_queue_new_dequeue_state(struct
deq_state->new_deq_ptr,
(unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr),
deq_state->new_cycle_state);
@@ -281,7 +281,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
deq_state->new_deq_seg,
deq_state->new_deq_ptr,
(u32) deq_state->new_cycle_state);
-@@ -536,11 +574,10 @@ static void handle_stopped_endpoint(stru
+@@ -553,11 +591,10 @@ static void handle_stopped_endpoint(stru
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
ep = &xhci->devs[slot_id]->eps[ep_index];
@@ -294,7 +294,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return;
}
-@@ -554,15 +591,36 @@ static void handle_stopped_endpoint(stru
+@@ -571,15 +608,36 @@ static void handle_stopped_endpoint(stru
xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
cur_td->first_trb,
(unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
@@ -333,7 +333,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/*
* The event handler won't see a completion for this TD anymore,
* so remove it from the endpoint ring's TD list. Keep it in
-@@ -576,11 +634,13 @@ static void handle_stopped_endpoint(stru
+@@ -593,11 +651,13 @@ static void handle_stopped_endpoint(stru
/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
xhci_queue_new_dequeue_state(xhci,
@@ -350,7 +350,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
ep->stopped_td = NULL;
ep->stopped_trb = NULL;
-@@ -740,6 +800,7 @@ static void handle_set_deq_completion(st
+@@ -757,6 +817,7 @@ static void handle_set_deq_completion(st
{
unsigned int slot_id;
unsigned int ep_index;
@@ -358,7 +358,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
struct xhci_ring *ep_ring;
struct xhci_virt_device *dev;
struct xhci_ep_ctx *ep_ctx;
-@@ -747,8 +808,19 @@ static void handle_set_deq_completion(st
+@@ -764,8 +825,19 @@ static void handle_set_deq_completion(st
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
@@ -379,7 +379,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
-@@ -793,7 +865,8 @@ static void handle_set_deq_completion(st
+@@ -810,7 +882,8 @@ static void handle_set_deq_completion(st
}
dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
@@ -389,7 +389,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
static void handle_reset_ep_completion(struct xhci_hcd *xhci,
-@@ -802,11 +875,9 @@ static void handle_reset_ep_completion(s
+@@ -819,11 +892,9 @@ static void handle_reset_ep_completion(s
{
int slot_id;
unsigned int ep_index;
@@ -401,7 +401,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* This command will only fail if the endpoint wasn't halted,
* but we don't care.
*/
-@@ -824,9 +895,9 @@ static void handle_reset_ep_completion(s
+@@ -841,9 +912,9 @@ static void handle_reset_ep_completion(s
false);
xhci_ring_cmd_db(xhci);
} else {
@@ -413,7 +413,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
}
-@@ -912,8 +983,10 @@ static void handle_cmd_completion(struct
+@@ -929,8 +1000,10 @@ static void handle_cmd_completion(struct
/* Input ctx add_flags are the endpoint index plus one */
ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
/* A usb_set_interface() call directly after clearing a halted
@@ -426,7 +426,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
*/
if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
ep_index != (unsigned int) -1 &&
-@@ -926,10 +999,10 @@ static void handle_cmd_completion(struct
+@@ -943,10 +1016,10 @@ static void handle_cmd_completion(struct
xhci_dbg(xhci, "Completed config ep cmd - "
"last ep index = %d, state = %d\n",
ep_index, ep_state);
@@ -439,7 +439,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
break;
}
bandwidth_change:
-@@ -1062,12 +1135,14 @@ struct xhci_segment *trb_in_td(struct xh
+@@ -1079,12 +1152,14 @@ struct xhci_segment *trb_in_td(struct xh
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
@@ -454,7 +454,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
xhci_queue_reset_ep(xhci, slot_id, ep_index);
xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
-@@ -1152,10 +1227,11 @@ static int handle_tx_event(struct xhci_h
+@@ -1169,10 +1244,11 @@ static int handle_tx_event(struct xhci_h
ep_index = TRB_TO_EP_ID(event->flags) - 1;
xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
ep = &xdev->eps[ep_index];
@@ -468,7 +468,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return -ENODEV;
}
-@@ -1286,7 +1362,7 @@ static int handle_tx_event(struct xhci_h
+@@ -1303,7 +1379,7 @@ static int handle_tx_event(struct xhci_h
td->urb->actual_length = 0;
xhci_cleanup_halted_endpoint(xhci,
@@ -477,7 +477,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
goto td_cleanup;
}
/*
-@@ -1435,6 +1511,7 @@ static int handle_tx_event(struct xhci_h
+@@ -1452,6 +1528,7 @@ static int handle_tx_event(struct xhci_h
*/
ep->stopped_td = td;
ep->stopped_trb = event_trb;
@@ -485,7 +485,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
} else if (xhci_requires_manual_halt_cleanup(xhci,
ep_ctx, trb_comp_code)) {
/* Other types of errors halt the endpoint, but the
-@@ -1443,7 +1520,7 @@ static int handle_tx_event(struct xhci_h
+@@ -1460,7 +1537,7 @@ static int handle_tx_event(struct xhci_h
* xHCI hardware manually.
*/
xhci_cleanup_halted_endpoint(xhci,
@@ -494,7 +494,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
} else {
/* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb)
-@@ -1639,14 +1716,24 @@ static int prepare_ring(struct xhci_hcd
+@@ -1656,14 +1733,24 @@ static int prepare_ring(struct xhci_hcd
static int prepare_transfer(struct xhci_hcd *xhci,
struct xhci_virt_device *xdev,
unsigned int ep_index,
@@ -520,7 +520,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
ep_ctx->ep_info & EP_STATE_MASK,
num_trbs, mem_flags);
if (ret)
-@@ -1666,9 +1753,9 @@ static int prepare_transfer(struct xhci_
+@@ -1683,9 +1770,9 @@ static int prepare_transfer(struct xhci_
(*td)->urb = urb;
urb->hcpriv = (void *) (*td);
/* Add this TD to the tail of the endpoint ring's TD list */
@@ -533,7 +533,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return 0;
}
-@@ -1734,7 +1821,7 @@ static void check_trb_math(struct urb *u
+@@ -1751,7 +1838,7 @@ static void check_trb_math(struct urb *u
}
static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
@@ -542,7 +542,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
struct xhci_generic_trb *start_trb, struct xhci_td *td)
{
/*
-@@ -1743,7 +1830,7 @@ static void giveback_first_trb(struct xh
+@@ -1760,7 +1847,7 @@ static void giveback_first_trb(struct xh
*/
wmb();
start_trb->field[3] |= start_cycle;
@@ -551,7 +551,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
/*
-@@ -1817,12 +1904,16 @@ static int queue_bulk_sg_tx(struct xhci_
+@@ -1834,12 +1921,16 @@ static int queue_bulk_sg_tx(struct xhci_
struct xhci_generic_trb *start_trb;
int start_cycle;
@@ -570,7 +570,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (trb_buff_len < 0)
return trb_buff_len;
/*
-@@ -1931,7 +2022,8 @@ static int queue_bulk_sg_tx(struct xhci_
+@@ -1948,7 +2039,8 @@ static int queue_bulk_sg_tx(struct xhci_
} while (running_total < urb->transfer_buffer_length);
check_trb_math(urb, num_trbs, running_total);
@@ -580,7 +580,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return 0;
}
-@@ -1953,7 +2045,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+@@ -1970,7 +2062,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
if (urb->num_sgs)
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
@@ -591,7 +591,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
num_trbs = 0;
/* How much data is (potentially) left before the 64KB boundary? */
-@@ -1980,7 +2074,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+@@ -1997,7 +2091,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
(unsigned long long)urb->transfer_dma,
num_trbs);
@@ -601,7 +601,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
num_trbs, urb, &td, mem_flags);
if (ret < 0)
return ret;
-@@ -2050,7 +2145,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
+@@ -2067,7 +2162,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
} while (running_total < urb->transfer_buffer_length);
check_trb_math(urb, num_trbs, running_total);
@@ -611,7 +611,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return 0;
}
-@@ -2067,7 +2163,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+@@ -2084,7 +2180,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
u32 field, length_field;
struct xhci_td *td;
@@ -622,7 +622,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/*
* Need to copy setup packet into setup TRB, so we can't use the setup
-@@ -2088,8 +2186,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+@@ -2105,8 +2203,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
*/
if (urb->transfer_buffer_length > 0)
num_trbs++;
@@ -634,7 +634,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (ret < 0)
return ret;
-@@ -2144,7 +2243,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+@@ -2161,7 +2260,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
/* Event on completion */
field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
@@ -644,7 +644,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return 0;
}
-@@ -2256,12 +2356,14 @@ int xhci_queue_stop_endpoint(struct xhci
+@@ -2273,12 +2373,14 @@ int xhci_queue_stop_endpoint(struct xhci
* This should not be used for endpoints that have streams enabled.
*/
static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
@@ -660,7 +660,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
u32 type = TRB_TYPE(TRB_SET_DEQ);
addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr);
-@@ -2272,7 +2374,7 @@ static int queue_set_tr_deq(struct xhci_
+@@ -2289,7 +2391,7 @@ static int queue_set_tr_deq(struct xhci_
return 0;
}
return queue_command(xhci, lower_32_bits(addr) | cycle_state,
diff --git a/usb/usb-xhci-fix-check-for-room-on-the-ring.patch b/usb/usb-xhci-fix-check-for-room-on-the-ring.patch
new file mode 100644
index 00000000000000..096f3c94f33557
--- /dev/null
+++ b/usb/usb-xhci-fix-check-for-room-on-the-ring.patch
@@ -0,0 +1,66 @@
+From sarah.a.sharp@linux.intel.com Thu May 20 10:48:52 2010
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Tue, 18 May 2010 16:05:26 -0700
+Subject: USB: xhci: Fix check for room on the ring.
+To: Greg KH <gregkh@suse.de>
+Cc: John Youn <John.Youn@synopsys.com>, linux-usb@vger.kernel.org
+Message-ID: <20100518230526.GA6092@xanatos>
+Content-Disposition: inline
+
+
+The length of the scatter gather list a driver can enqueue is limited by
+the bus' sg_tablesize to 62 entries. Each entry will be described by at
+least one transfer request block (TRB). If the entry's buffer crosses a
+64KB boundary, then that entry will have to be described by two or more
+TRBs. So even if the USB device driver respects sg_tablesize, the whole
+scatter list may take more than 62 TRBs to describe, and won't fit on
+the ring.
+
+Don't assume that an empty ring means there is enough room on the
+transfer ring. The old code would unconditionally queue this too-large
+transfer, and over write the beginning of the transfer. This would mean
+the cycle bit was unchanged in those overwritten transfers, causing the
+hardware to think it didn't own the TRBs, and the host would seem to
+hang.
+
+Now drivers may see submit_urb() fail with -ENOMEM if the transfers are
+too big to fit on the ring.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -242,10 +242,27 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
+ int i;
+ union xhci_trb *enq = ring->enqueue;
+ struct xhci_segment *enq_seg = ring->enq_seg;
++ struct xhci_segment *cur_seg;
++ unsigned int left_on_ring;
+
+ /* Check if ring is empty */
+- if (enq == ring->dequeue)
++ if (enq == ring->dequeue) {
++ /* Can't use link trbs */
++ left_on_ring = TRBS_PER_SEGMENT - 1;
++ for (cur_seg = enq_seg->next; cur_seg != enq_seg;
++ cur_seg = cur_seg->next)
++ left_on_ring += TRBS_PER_SEGMENT - 1;
++
++ /* Always need one TRB free in the ring. */
++ left_on_ring -= 1;
++ if (num_trbs > left_on_ring) {
++ xhci_warn(xhci, "Not enough room on ring; "
++ "need %u TRBs, %u TRBs left\n",
++ num_trbs, left_on_ring);
++ return 0;
++ }
+ return 1;
++ }
+ /* Make sure there's an extra empty TRB available */
+ for (i = 0; i <= num_trbs; ++i) {
+ if (enq == ring->dequeue)
+--
+1.6.3.3
+
diff --git a/usb/usb-xhci-fix-compiler-warning.patch b/usb/usb-xhci-fix-compiler-warning.patch
index 869d4e16460771..30a22e21f59830 100644
--- a/usb/usb-xhci-fix-compiler-warning.patch
+++ b/usb/usb-xhci-fix-compiler-warning.patch
@@ -14,7 +14,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -1726,7 +1726,6 @@ static int prepare_ring(struct xhci_hcd
+@@ -1743,7 +1743,6 @@ static int prepare_ring(struct xhci_hcd
if (enqueue_is_link_trb(ep_ring)) {
struct xhci_ring *ring = ep_ring;
union xhci_trb *next;
diff --git a/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch b/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch
index 4e7dd916de1bb7..3a6ac0d146da24 100644
--- a/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch
+++ b/usb/usb-xhci-fix-wrong-usage-of-macro-trb_type.patch
@@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -373,7 +373,8 @@ static struct xhci_segment *find_trb_seg
+@@ -390,7 +390,8 @@ static struct xhci_segment *find_trb_seg
while (cur_seg->trbs > trb ||
&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
@@ -32,7 +32,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
(generic_trb->field[3] & LINK_TOGGLE))
*cycle_state = ~(*cycle_state) & 0x1;
cur_seg = cur_seg->next;
-@@ -438,7 +439,7 @@ void xhci_find_new_dequeue_state(struct
+@@ -455,7 +456,7 @@ void xhci_find_new_dequeue_state(struct
BUG();
trb = &state->new_deq_ptr->generic;
@@ -41,7 +41,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
(trb->field[3] & LINK_TOGGLE))
state->new_cycle_state = ~(state->new_cycle_state) & 0x1;
next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
-@@ -1487,8 +1488,10 @@ static int handle_tx_event(struct xhci_h
+@@ -1504,8 +1505,10 @@ static int handle_tx_event(struct xhci_h
for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
cur_trb != event_trb;
next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
diff --git a/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch b/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch
new file mode 100644
index 00000000000000..591281de20fb36
--- /dev/null
+++ b/usb/usb-xhci-limit-bus-sg_tablesize-to-62-trbs.patch
@@ -0,0 +1,36 @@
+From sarah.a.sharp@linux.intel.com Thu May 20 10:48:18 2010
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Tue, 18 May 2010 16:05:21 -0700
+Subject: USB: xhci: Limit bus sg_tablesize to 62 TRBs.
+To: Greg KH <gregkh@suse.de>
+Cc: John Youn <John.Youn@synopsys.com>, linux-usb@vger.kernel.org
+Message-ID: <20100518230521.GA6036@xanatos>
+Content-Disposition: inline
+
+
+When a scatter-gather list is enqueued to the xHCI driver, it translates
+each entry into a transfer request block (TRB). Only 63 TRBs can be
+used per ring segment, and there must be one additional TRB reserved to
+make sure the hardware does not think the ring is empty (so the enqueue
+pointer doesn't equal the dequeue pointer). Limit the bus sg_tablesize
+to 62 TRBs.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -54,7 +54,7 @@ static int xhci_pci_setup(struct usb_hcd
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ int retval;
+
+- hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 1;
++ hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+
+ xhci->cap_regs = hcd->regs;
+ xhci->op_regs = hcd->regs +
diff --git a/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch b/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch
index be411d6ec60c92..ada1085f7f3862 100644
--- a/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch
+++ b/usb/usb-xhci-set-stream-id-to-0-after-cleaning-up-stalls.patch
@@ -21,7 +21,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -1149,6 +1149,7 @@ static void xhci_cleanup_halted_endpoint
+@@ -1166,6 +1166,7 @@ static void xhci_cleanup_halted_endpoint
ep->stopped_td = NULL;
ep->stopped_trb = NULL;
diff --git a/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch b/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch
index d780c67e5b4663..37aaecf4cbb95e 100644
--- a/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch
+++ b/usb/usb-xhci-transfer-ring-link-trb-activation-change.patch
@@ -65,9 +65,9 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
-@@ -243,6 +244,13 @@ static int room_on_ring(struct xhci_hcd
- union xhci_trb *enq = ring->enqueue;
- struct xhci_segment *enq_seg = ring->enq_seg;
+@@ -245,6 +246,13 @@ static int room_on_ring(struct xhci_hcd
+ struct xhci_segment *cur_seg;
+ unsigned int left_on_ring;
+ /* If we are currently pointing to a link TRB, advance the
+ * enqueue pointer before checking for space */
@@ -77,9 +77,9 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+ }
+
/* Check if ring is empty */
- if (enq == ring->dequeue)
- return 1;
-@@ -1711,6 +1719,43 @@ static int prepare_ring(struct xhci_hcd
+ if (enq == ring->dequeue) {
+ /* Can't use link trbs */
+@@ -1728,6 +1736,43 @@ static int prepare_ring(struct xhci_hcd
xhci_err(xhci, "ERROR no room on ep ring\n");
return -ENOMEM;
}
diff --git a/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch b/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch
index 3b2cf069071721..6043170def5b43 100644
--- a/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch
+++ b/usb/xhci-add-memory-allocation-for-usb3-bulk-streams.patch
@@ -488,7 +488,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (!xhci->cmd_ring)
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
-@@ -306,6 +306,10 @@ static void ring_ep_doorbell(struct xhci
+@@ -323,6 +323,10 @@ static void ring_ep_doorbell(struct xhci
ep_state = ep->ep_state;
/* Don't ring the doorbell for this endpoint if there are pending
* cancellations because the we don't want to interrupt processing.
@@ -499,7 +499,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
*/
if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
&& !(ep_state & EP_HALTED)) {
-@@ -899,8 +903,9 @@ static void handle_cmd_completion(struct
+@@ -916,8 +920,9 @@ static void handle_cmd_completion(struct
* Configure endpoint commands can come from the USB core
* configuration or alt setting changes, or because the HW
* needed an extra configure endpoint command after a reset