aboutsummaryrefslogtreecommitdiff
path: root/hw/i2c.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-12-04 20:39:20 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-01-27 10:50:47 -0600
commitb5ea932781954355a9880e2744722cd05cc496f9 (patch)
treef47482844578c1dffdae93dc3ec103a101097a71 /hw/i2c.c
parent9e07bdf816b186632cda9651ac29bba76d299c03 (diff)
i2c: smbus: convert to QEMU Object Model
This converts two types because smbus is implemented as a subclass of i2c. It's extremely difficult to convert these two independently. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/i2c.c')
-rw-r--r--hw/i2c.c83
1 files changed, 65 insertions, 18 deletions
diff --git a/hw/i2c.c b/hw/i2c.c
index 9efe70c29d..9e5d3dfb1a 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -83,6 +83,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
{
DeviceState *qdev;
I2CSlave *slave = NULL;
+ I2CSlaveClass *sc;
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
@@ -92,24 +93,33 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
}
}
- if (!slave)
+ if (!slave) {
return 1;
+ }
+ sc = I2C_SLAVE_GET_CLASS(slave);
/* If the bus is already busy, assume this is a repeated
start condition. */
bus->current_dev = slave;
- slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ if (sc->event) {
+ sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ }
return 0;
}
void i2c_end_transfer(i2c_bus *bus)
{
I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_FINISH);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_FINISH);
+ }
bus->current_dev = NULL;
}
@@ -117,31 +127,50 @@ void i2c_end_transfer(i2c_bus *bus)
int i2c_send(i2c_bus *bus, uint8_t data)
{
I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
- return dev->info->send(dev, data);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->send) {
+ return sc->send(dev, data);
+ }
+
+ return -1;
}
int i2c_recv(i2c_bus *bus)
{
I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
+
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->recv) {
+ return sc->recv(dev);
+ }
- return dev->info->recv(dev);
+ return -1;
}
void i2c_nack(i2c_bus *bus)
{
I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_NACK);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_NACK);
+ }
}
static int i2c_slave_post_load(void *opaque, int version_id)
@@ -169,20 +198,23 @@ const VMStateDescription vmstate_i2c_slave = {
static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
{
- I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
+ I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
- s->info = info;
+ return sc->init(s);
+}
- return info->init(s);
+void i2c_register_slave_subclass(DeviceInfo *info, const char *parent)
+{
+ assert(info->size >= sizeof(I2CSlave));
+ info->init = i2c_slave_qdev_init;
+ info->bus_info = &i2c_bus_info;
+ qdev_register_subclass(info, parent);
}
-void i2c_register_slave(I2CSlaveInfo *info)
+void i2c_register_slave(DeviceInfo *info)
{
- assert(info->qdev.size >= sizeof(I2CSlave));
- info->qdev.init = i2c_slave_qdev_init;
- info->qdev.bus_info = &i2c_bus_info;
- qdev_register(&info->qdev);
+ i2c_register_slave_subclass(info, TYPE_I2C_SLAVE);
}
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
@@ -194,3 +226,18 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
qdev_init_nofail(dev);
return dev;
}
+
+static TypeInfo i2c_slave_type_info = {
+ .name = TYPE_I2C_SLAVE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(I2CSlave),
+ .abstract = true,
+ .class_size = sizeof(I2CSlaveClass),
+};
+
+static void i2c_slave_register_devices(void)
+{
+ type_register_static(&i2c_slave_type_info);
+}
+
+device_init(i2c_slave_register_devices);