aboutsummaryrefslogtreecommitdiff
path: root/hw/i2c/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/i2c/core.c')
-rw-r--r--hw/i2c/core.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index d4ba8146bf..bed594fe59 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -185,22 +185,39 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv)
void i2c_bus_master(I2CBus *bus, QEMUBH *bh)
{
- if (i2c_bus_busy(bus)) {
- I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1);
- node->bh = bh;
+ I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1);
+ node->bh = bh;
+
+ QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry);
+}
+
+void i2c_schedule_pending_master(I2CBus *bus)
+{
+ I2CPendingMaster *node;
- QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry);
+ if (i2c_bus_busy(bus)) {
+ /* someone is already controlling the bus; wait for it to release it */
+ return;
+ }
+ if (QSIMPLEQ_EMPTY(&bus->pending_masters)) {
return;
}
- bus->bh = bh;
+ node = QSIMPLEQ_FIRST(&bus->pending_masters);
+ bus->bh = node->bh;
+
+ QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry);
+ g_free(node);
+
qemu_bh_schedule(bus->bh);
}
void i2c_bus_release(I2CBus *bus)
{
bus->bh = NULL;
+
+ i2c_schedule_pending_master(bus);
}
int i2c_start_recv(I2CBus *bus, uint8_t address)
@@ -234,16 +251,6 @@ void i2c_end_transfer(I2CBus *bus)
g_free(node);
}
bus->broadcast = false;
-
- if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) {
- I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters);
- bus->bh = node->bh;
-
- QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry);
- g_free(node);
-
- qemu_bh_schedule(bus->bh);
- }
}
int i2c_send(I2CBus *bus, uint8_t data)