diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index ec299ae17a5a..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 */ |
| @@ -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 | ||
