aboutsummaryrefslogtreecommitdiff
path: root/hw/i2c
diff options
context:
space:
mode:
authorPatrick Venture <venture@google.com>2021-04-12 12:45:20 -0700
committerCorey Minyard <cminyard@mvista.com>2021-04-15 07:10:06 -0500
commit513ca82d8982463aca98aa01dcf584e0b4fc0982 (patch)
tree6653797e4ea6b778f9a10f73926ebc2415a424b4 /hw/i2c
parentb98ec6896ee88f1dcdd7098af25bcb6ee0fc50f0 (diff)
downloadqemu-513ca82d8982463aca98aa01dcf584e0b4fc0982.zip
qemu-513ca82d8982463aca98aa01dcf584e0b4fc0982.tar.gz
qemu-513ca82d8982463aca98aa01dcf584e0b4fc0982.tar.bz2
hw/i2c: add match method for device search
At the start of an i2c transaction, the i2c bus searches its list of children to identify which devices correspond to the address (or broadcast). Now the I2CSlave device has a method "match" that encapsulates the lookup behavior. This allows the behavior to be changed to support devices, such as i2c muxes. Tested: A BMC firmware was booted to userspace and i2c devices were detected. Signed-off-by: Patrick Venture <venture@google.com> Reviewed-by: Hao Wu <wuhaotsh@google.com> Message-Id: <20210412194522.664594-3-venture@google.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
Diffstat (limited to 'hw/i2c')
-rw-r--r--hw/i2c/core.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 21ec52a..d03b0ee 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -118,10 +118,9 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
I2CSlave *candidate = I2C_SLAVE(qdev);
- if ((candidate->address == address) || (bus->broadcast)) {
- node = g_malloc(sizeof(struct I2CNode));
- node->elt = candidate;
- QLIST_INSERT_HEAD(&bus->current_devs, node, next);
+ sc = I2C_SLAVE_GET_CLASS(candidate);
+ if (sc->match_and_add(candidate, address, bus->broadcast,
+ &bus->current_devs)) {
if (!bus->broadcast) {
break;
}
@@ -290,12 +289,28 @@ I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr)
return dev;
}
+static bool i2c_slave_match(I2CSlave *candidate, uint8_t address,
+ bool broadcast, I2CNodeList *current_devs)
+{
+ if ((candidate->address == address) || (broadcast)) {
+ I2CNode *node = g_malloc(sizeof(struct I2CNode));
+ node->elt = candidate;
+ QLIST_INSERT_HEAD(current_devs, node, next);
+ return true;
+ }
+
+ /* Not found and not broadcast. */
+ return false;
+}
+
static void i2c_slave_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
set_bit(DEVICE_CATEGORY_MISC, k->categories);
k->bus_type = TYPE_I2C_BUS;
device_class_set_props(k, i2c_props);
+ sc->match_and_add = i2c_slave_match;
}
static const TypeInfo i2c_slave_type_info = {