diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-at91.c')
-rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 79a68999a696..917d54588d95 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c | |||
@@ -101,6 +101,7 @@ struct at91_twi_dev { | |||
101 | unsigned twi_cwgr_reg; | 101 | unsigned twi_cwgr_reg; |
102 | struct at91_twi_pdata *pdata; | 102 | struct at91_twi_pdata *pdata; |
103 | bool use_dma; | 103 | bool use_dma; |
104 | bool recv_len_abort; | ||
104 | struct at91_twi_dma dma; | 105 | struct at91_twi_dma dma; |
105 | }; | 106 | }; |
106 | 107 | ||
@@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) | |||
267 | *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; | 268 | *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; |
268 | --dev->buf_len; | 269 | --dev->buf_len; |
269 | 270 | ||
271 | /* return if aborting, we only needed to read RHR to clear RXRDY*/ | ||
272 | if (dev->recv_len_abort) | ||
273 | return; | ||
274 | |||
270 | /* handle I2C_SMBUS_BLOCK_DATA */ | 275 | /* handle I2C_SMBUS_BLOCK_DATA */ |
271 | if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { | 276 | if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { |
272 | dev->msg->flags &= ~I2C_M_RECV_LEN; | 277 | /* ensure length byte is a valid value */ |
273 | dev->buf_len += *dev->buf; | 278 | if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) { |
274 | dev->msg->len = dev->buf_len + 1; | 279 | dev->msg->flags &= ~I2C_M_RECV_LEN; |
275 | dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); | 280 | dev->buf_len += *dev->buf; |
281 | dev->msg->len = dev->buf_len + 1; | ||
282 | dev_dbg(dev->dev, "received block length %d\n", | ||
283 | dev->buf_len); | ||
284 | } else { | ||
285 | /* abort and send the stop by reading one more byte */ | ||
286 | dev->recv_len_abort = true; | ||
287 | dev->buf_len = 1; | ||
288 | } | ||
276 | } | 289 | } |
277 | 290 | ||
278 | /* send stop if second but last byte has been read */ | 291 | /* send stop if second but last byte has been read */ |
@@ -421,8 +434,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) | |||
421 | } | 434 | } |
422 | } | 435 | } |
423 | 436 | ||
424 | ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, | 437 | ret = wait_for_completion_io_timeout(&dev->cmd_complete, |
425 | dev->adapter.timeout); | 438 | dev->adapter.timeout); |
426 | if (ret == 0) { | 439 | if (ret == 0) { |
427 | dev_err(dev->dev, "controller timed out\n"); | 440 | dev_err(dev->dev, "controller timed out\n"); |
428 | at91_init_twi_bus(dev); | 441 | at91_init_twi_bus(dev); |
@@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) | |||
444 | ret = -EIO; | 457 | ret = -EIO; |
445 | goto error; | 458 | goto error; |
446 | } | 459 | } |
460 | if (dev->recv_len_abort) { | ||
461 | dev_err(dev->dev, "invalid smbus block length recvd\n"); | ||
462 | ret = -EPROTO; | ||
463 | goto error; | ||
464 | } | ||
465 | |||
447 | dev_dbg(dev->dev, "transfer complete\n"); | 466 | dev_dbg(dev->dev, "transfer complete\n"); |
448 | 467 | ||
449 | return 0; | 468 | return 0; |
@@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) | |||
500 | dev->buf_len = m_start->len; | 519 | dev->buf_len = m_start->len; |
501 | dev->buf = m_start->buf; | 520 | dev->buf = m_start->buf; |
502 | dev->msg = m_start; | 521 | dev->msg = m_start; |
522 | dev->recv_len_abort = false; | ||
503 | 523 | ||
504 | ret = at91_do_twi_transfer(dev); | 524 | ret = at91_do_twi_transfer(dev); |
505 | 525 | ||