Skip to content

Commit

Permalink
spi: spi_write_then_read() bugfixes
Browse files Browse the repository at this point in the history
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>
Cc: <stable@kernel.org>		[2.6.28.x, 2.6.29.x]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
David Brownell authored and Linus Torvalds committed Apr 13, 2009
1 parent 0769c29 commit bdff549
Showing 1 changed file with 14 additions and 8 deletions.
22 changes: 14 additions & 8 deletions drivers/spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ int spi_write_then_read(struct spi_device *spi,

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,
Expand All @@ -669,9 +669,15 @@ int spi_write_then_read(struct spi_device *spi,
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)) {
Expand All @@ -682,15 +688,15 @@ int spi_write_then_read(struct spi_device *spi,
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);
Expand Down

0 comments on commit bdff549

Please sign in to comment.