aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-10-24 19:12:29 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-11-07 10:01:15 +0000
commit9706e0162d2405218fd7376ffdf13baed8569a4b (patch)
treefc0b5ad553ae5602a69816ffa980695a43311443
parent3823b9db77e753041c04c161ac9f4d4cfc661520 (diff)
hw/i2c/bitbang_i2c: Handle NACKs from devicespull-target-arm-20161107
If the guest attempts to talk to a nonexistent device over i2c, the i2c_start_transfer() function will return non-zero, indicating that the bus is signalling a NACK. Similarly, if the i2c_send() function returns nonzero then the target device returned a NACK. Handle this possibility in the bitbang_i2c code, by returning the state machine to the STOPPED state and returning the NACK bit to the guest. This bit of missing functionality was spotted by Coverity (it noticed that we weren't checking the return value from i2c_start_transfer()). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1477332749-27098-1-git-send-email-peter.maydell@linaro.org
-rw-r--r--hw/i2c/bitbang_i2c.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c
index d3a29891f8..8be88ee265 100644
--- a/hw/i2c/bitbang_i2c.c
+++ b/hw/i2c/bitbang_i2c.c
@@ -130,14 +130,25 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
return bitbang_i2c_ret(i2c, 1);
case WAITING_FOR_ACK:
+ {
+ int ret;
+
if (i2c->current_addr < 0) {
i2c->current_addr = i2c->buffer;
DPRINTF("Address 0x%02x\n", i2c->current_addr);
- i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
- i2c->current_addr & 1);
+ ret = i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
+ i2c->current_addr & 1);
} else {
DPRINTF("Sent 0x%02x\n", i2c->buffer);
- i2c_send(i2c->bus, i2c->buffer);
+ ret = i2c_send(i2c->bus, i2c->buffer);
+ }
+ if (ret) {
+ /* NACK (either addressing a nonexistent device, or the
+ * device we were sending to decided to NACK us).
+ */
+ DPRINTF("Got NACK\n");
+ bitbang_i2c_enter_stop(i2c);
+ return bitbang_i2c_ret(i2c, 1);
}
if (i2c->current_addr & 1) {
i2c->state = RECEIVING_BIT7;
@@ -145,7 +156,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
i2c->state = SENDING_BIT7;
}
return bitbang_i2c_ret(i2c, 0);
-
+ }
case RECEIVING_BIT7:
i2c->buffer = i2c_recv(i2c->bus);
DPRINTF("RX byte 0x%02x\n", i2c->buffer);