]> git.proxmox.com Git - mirror_qemu.git/commitdiff
hw/i2c/bitbang_i2c: Handle NACKs from devices
authorPeter Maydell <peter.maydell@linaro.org>
Mon, 24 Oct 2016 18:12:29 +0000 (19:12 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Mon, 7 Nov 2016 10:01:15 +0000 (10:01 +0000)
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

hw/i2c/bitbang_i2c.c

index d3a29891f8e25d0410597a799ee2d18527bca8b2..8be88ee265c130c1dcdaf67c327f962606e0bcd7 100644 (file)
@@ -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);