| From 68890fb0bae12f076377dd6a9371be0289b98b7b Mon Sep 17 00:00:00 2001 |
| From: David Brownell <dbrownell@users.sourceforge.net> |
| Date: Mon, 13 Apr 2009 22:35:03 +0000 |
| Subject: spi: spi_write_then_read() bugfixes |
| |
| From: David Brownell <dbrownell@users.sourceforge.net> |
| |
| upstream commit: bdff549ebeff92b1a6952e5501caf16a6f8898c8 |
| |
| The "simplify spi_write_then_read()" patch included two regressions from |
| the 2.6.27 behaviors: |
| |
| - The data it wrote out during the (full duplex) read side |
| of the transfer was not zeroed. |
| |
| - It fails completely on half duplex hardware, such as |
| Microwire and most "3-wire" SPI variants. |
| |
| So, revert that patch. A revised version should be submitted at some |
| point, which can get the speedup on standard hardware (full duplex) |
| without breaking on less-capable half-duplex stuff. |
| |
| Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| drivers/spi/spi.c | 22 ++++++++++++++-------- |
| 1 file changed, 14 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/spi/spi.c |
| +++ b/drivers/spi/spi.c |
| @@ -660,7 +660,7 @@ int spi_write_then_read(struct spi_devic |
| |
| int status; |
| struct spi_message message; |
| - struct spi_transfer x; |
| + struct spi_transfer x[2]; |
| u8 *local_buf; |
| |
| /* Use preallocated DMA-safe buffer. We can't avoid copying here, |
| @@ -671,9 +671,15 @@ int spi_write_then_read(struct spi_devic |
| return -EINVAL; |
| |
| spi_message_init(&message); |
| - memset(&x, 0, sizeof x); |
| - x.len = n_tx + n_rx; |
| - spi_message_add_tail(&x, &message); |
| + memset(x, 0, sizeof x); |
| + if (n_tx) { |
| + x[0].len = n_tx; |
| + spi_message_add_tail(&x[0], &message); |
| + } |
| + if (n_rx) { |
| + x[1].len = n_rx; |
| + spi_message_add_tail(&x[1], &message); |
| + } |
| |
| /* ... unless someone else is using the pre-allocated buffer */ |
| if (!mutex_trylock(&lock)) { |
| @@ -684,15 +690,15 @@ int spi_write_then_read(struct spi_devic |
| local_buf = buf; |
| |
| memcpy(local_buf, txbuf, n_tx); |
| - x.tx_buf = local_buf; |
| - x.rx_buf = local_buf; |
| + x[0].tx_buf = local_buf; |
| + x[1].rx_buf = local_buf + n_tx; |
| |
| /* do the i/o */ |
| status = spi_sync(spi, &message); |
| if (status == 0) |
| - memcpy(rxbuf, x.rx_buf + n_tx, n_rx); |
| + memcpy(rxbuf, x[1].rx_buf, n_rx); |
| |
| - if (x.tx_buf == buf) |
| + if (x[0].tx_buf == buf) |
| mutex_unlock(&lock); |
| else |
| kfree(local_buf); |