diff --git a/hw/i2c.c b/hw/i2c.c index e590801af30957268b28dd4b2d1dd3fd9fb6b7e1..5d283fb4cb723999bc2d573fcffaa1fbfe9fcc1f 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -14,14 +14,38 @@ struct i2c_bus { i2c_slave *current_dev; i2c_slave *dev; + int saved_address; }; +static void i2c_bus_save(QEMUFile *f, void *opaque) +{ + i2c_bus *bus = (i2c_bus *)opaque; + + qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : -1); +} + +static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id) +{ + i2c_bus *bus = (i2c_bus *)opaque; + + if (version_id != 1) + return -EINVAL; + + /* The bus is loaded before attached devices, so load and save the + current device id. Devices will check themselves as loaded. */ + bus->saved_address = qemu_get_be32(f); + bus->current_dev = NULL; + + return 0; +} + /* Create a new I2C bus. */ i2c_bus *i2c_init_bus(void) { i2c_bus *bus; bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); + register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); return bus; } @@ -37,6 +61,7 @@ i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size) dev->address = address; dev->next = bus->dev; bus->dev = dev; + dev->bus = bus; return dev; } @@ -115,28 +140,6 @@ void i2c_nack(i2c_bus *bus) dev->event(dev, I2C_NACK); } -void i2c_bus_save(QEMUFile *f, i2c_bus *bus) -{ - qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00); -} - -void i2c_bus_load(QEMUFile *f, i2c_bus *bus) -{ - i2c_slave *dev; - uint8_t address = qemu_get_byte(f); - - if (address) { - for (dev = bus->dev; dev; dev = dev->next) - if (dev->address == address) { - bus->current_dev = dev; - return; - } - - fprintf(stderr, "%s: I2C slave with address %02x disappeared\n", - __FUNCTION__, address); - } -} - void i2c_slave_save(QEMUFile *f, i2c_slave *dev) { qemu_put_byte(f, dev->address); @@ -145,4 +148,6 @@ void i2c_slave_save(QEMUFile *f, i2c_slave *dev) void i2c_slave_load(QEMUFile *f, i2c_slave *dev) { dev->address = qemu_get_byte(f); + if (dev->bus->saved_address == dev->address) + dev->bus->current_dev = dev; } diff --git a/hw/i2c.h b/hw/i2c.h index f297237b728b99f195e10de629095bf1c882d99b..d3e4352b1ffc040f6602cbf13c2607def4085e1b 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -30,6 +30,7 @@ struct i2c_slave /* Remaining fields for internal use by the I2C code. */ int address; void *next; + i2c_bus *bus; }; i2c_bus *i2c_init_bus(void); @@ -41,8 +42,6 @@ void i2c_end_transfer(i2c_bus *bus); void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); -void i2c_bus_save(QEMUFile *f, i2c_bus *bus); -void i2c_bus_load(QEMUFile *f, i2c_bus *bus); void i2c_slave_save(QEMUFile *f, i2c_slave *dev); void i2c_slave_load(QEMUFile *f, i2c_slave *dev); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index cb6670c3546b0685673b74f424ad079075c32b7a..fd663d9da1788208e2db988dd2a41d6cb00834dc 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1466,7 +1466,6 @@ static void pxa2xx_i2c_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->ibmr); qemu_put_8s(f, &s->data); - i2c_bus_save(f, s->bus); i2c_slave_save(f, &s->slave); } @@ -1474,12 +1473,14 @@ static int pxa2xx_i2c_load(QEMUFile *f, void *opaque, int version_id) { struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + if (version_id != 1) + return -EINVAL; + qemu_get_be16s(f, &s->control); qemu_get_be16s(f, &s->status); qemu_get_8s(f, &s->ibmr); qemu_get_8s(f, &s->data); - i2c_bus_load(f, s->bus); i2c_slave_load(f, &s->slave); return 0; } @@ -1488,6 +1489,7 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, qemu_irq irq, uint32_t page_size) { int iomemtype; + /* FIXME: Should the slave device really be on a separate bus? */ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s)); @@ -1502,7 +1504,7 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, pxa2xx_i2c_writefn, s); cpu_register_physical_memory(s->base & ~page_size, page_size, iomemtype); - register_savevm("pxa2xx_i2c", base, 0, + register_savevm("pxa2xx_i2c", base, 1, pxa2xx_i2c_save, pxa2xx_i2c_load, s); return s;