qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH RFC] i2c: Add AT24Cxx EEPROM model


From: Tim Sander
Subject: [Qemu-devel] [PATCH RFC] i2c: Add AT24Cxx EEPROM model
Date: Thu, 17 Dec 2015 14:09:13 +0100
User-agent: KMail/4.14.3 (Linux/4.1.0quirk-00001-gf1e27b0-dirty; KDE/4.14.13; x86_64; ; )

Hi

Below is a patch from Jan Kiszka 
https://lists.gnu.org/archive/html/qemu-devel/2013-04/msg05714.html
but in one part and adapted to block layer changes. I would like to get
this work mainlined and my question is whats missing to get this stuff 
mainlined?
As far as i understand Jan is ok with this effort.

Best regards
Tim

Original patch descriptions:
Some devices react on multiple addresses. To emulate this, we could
register them multiple times, but that is cumbersome. The AT24C16, e.g.
listens on 8 different addresses.

Instead, introduce a device address mask that is applied on the
transmitted address before matching it against the stored one. Moreover,
the transmitted address is passed as additional parameter to the event
callback of the device.

This implements I2C EEPROMs of the AT24Cxx series. Sizes from 1Kbit to
1024Kbit are supported. Each EEPROM is backed by a block device. Its
size can be explicitly specified by selecting the exact device type
(required for sizes < 512, the blockdev sector size) or implicitly by
providing a block device image of the corresponding size. Device
addresses are built from the device number property. Write protection
can be configured by declaring the block device read-only.

---                                                                             
                                                                                
                   
 hw/arm/pxa2xx.c        |   3 +-                                                
                                                                                
                   
 hw/arm/tosa.c          |   2 +-                                                
                                                                                
                   
 hw/arm/z2.c            |   2 +-                                                
                                                                                
                   
 hw/audio/wm8750.c      |   2 +-                                                
                                                                                
                   
 hw/display/ssd0303.c   |   2 +-                                                
                                                                                
                   
 hw/gpio/max7310.c      |   2 +-                                                
                                                                                
                   
 hw/i2c/core.c          |  16 +-                                                
                                                                                
                   
 hw/i2c/smbus.c         |   2 +-                                                
                                                                                
                   
 hw/input/lm832x.c      |   2 +-                                                
                                                                                
                   
 hw/misc/tmp105.c       |   2 +-                                                
                                                                                
                   
 hw/nvram/Makefile.objs |   1 +                                                 
                                                                                
                   
 hw/nvram/at24.c        | 392 +++++++++++++++++++++++++++++++++++++++++++++++++ 
                                                                                
                   
 hw/timer/ds1338.c      |   2 +-                                                
                                                                                
                   
 hw/timer/twl92230.c    |   2 +-                                                
                                                                                
                   
 include/hw/i2c/i2c.h   |   4 +-                                                
                                                                                
                   
 15 files changed, 420 insertions(+), 16 deletions(-)                           
                                                                                
                   
 create mode 100644 hw/nvram/at24.c                                             
                                                                                
                   
                                                                                
                                                                                
                   
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c                                  
                                                                                
                   
index 79d22d9..4e7bb42 100644                                                   
                                                                                
                   
--- a/hw/arm/pxa2xx.c                                                           
                                                                                
                   
+++ b/hw/arm/pxa2xx.c                                                           
                                                                                
                   
@@ -1255,7 +1255,8 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)          
                                                                                
                   
 }                                                                              
                                                                                
                   
                                                                                
                                                                                
                   
 /* These are only stubs now.  */                                               
                                                                                
                   
-static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)              
                                                                                
                   
+static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event,              
                                                                                
                   
+                             uint8_t param)                                    
                                                                                
                   
 {                                                                              
                                                                                
                   
     PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);                        
                                                                                
                   
     PXA2xxI2CState *s = slave->host;                                           
                                                                                
                   
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c                                      
                                                                                
                   
index 02814d7..abec18f 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -161,7 +161,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
+static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     TosaDACState *s = TOSA_DAC(i2c);
 
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index b44eb76..208d393 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -221,7 +221,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void aer915_event(I2CSlave *i2c, enum i2c_event event)
+static void aer915_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     AER915State *s = AER915(i2c);
 
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index b50b331..ed01583 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -302,7 +302,7 @@ static void wm8750_reset(I2CSlave *i2c)
     s->i2c_len = 0;
 }
 
-static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     WM8750State *s = WM8750(i2c);
 
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index f6804fb..dc18eeb 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -178,7 +178,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
+static void ssd0303_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     ssd0303_state *s = SSD0303(i2c);
 
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
index 2f59b13..d3eccb5 100644
--- a/hw/gpio/max7310.c
+++ b/hw/gpio/max7310.c
@@ -128,7 +128,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void max7310_event(I2CSlave *i2c, enum i2c_event event)
+static void max7310_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     MAX7310State *s = MAX7310(i2c);
     s->len = 0;
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 5a64026..cefef1a 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -75,6 +75,13 @@ void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
     dev->address = address;
 }
 
+/* devices can appear multiple times on the I2C bus
+   multiple registration can be avoided using this mask */
+void i2c_set_slave_address_mask(I2CSlave *dev, uint8_t mask)
+{
+    dev->address_mask = mask;
+}
+
 /* Return nonzero if bus is busy.  */
 int i2c_bus_busy(I2CBus *bus)
 {
@@ -92,7 +99,7 @@ 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) {
+        if (candidate->address == (address & candidate->address_mask)) {
             slave = candidate;
             break;
         }
@@ -107,7 +114,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int 
recv)
        start condition.  */
     bus->current_dev = slave;
     if (sc->event) {
-        sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+        sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND, address);
     }
     return 0;
 }
@@ -123,7 +130,7 @@ void i2c_end_transfer(I2CBus *bus)
 
     sc = I2C_SLAVE_GET_CLASS(dev);
     if (sc->event) {
-        sc->event(dev, I2C_FINISH);
+        sc->event(dev, I2C_FINISH, 0);
     }
 
     bus->current_dev = NULL;
@@ -174,7 +181,7 @@ void i2c_nack(I2CBus *bus)
 
     sc = I2C_SLAVE_GET_CLASS(dev);
     if (sc->event) {
-        sc->event(dev, I2C_NACK);
+        sc->event(dev, I2C_NACK, 0);
     }
 }
 
@@ -205,6 +212,7 @@ static int i2c_slave_qdev_init(DeviceState *dev)
     I2CSlave *s = I2C_SLAVE(dev);
     I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
 
+    s->address_mask = 0x7f;
     return sc->init(s);
 }
 
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 6e27ae8..5bb5f94 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -66,7 +66,7 @@ static void smbus_do_write(SMBusDevice *dev)
     }
 }
 
-static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
+static void smbus_i2c_event(I2CSlave *s, enum i2c_event event, uint8_t param)
 {
     SMBusDevice *dev = SMBUS_DEVICE(s);
 
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
index 530a6e0..87c4b16 100644
--- a/hw/input/lm832x.c
+++ b/hw/input/lm832x.c
@@ -382,7 +382,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int 
byte, uint8_t value)
     }
 }
 
-static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
+static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     LM823KbdState *s = LM8323(i2c);
 
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index f3fe8b8..d3d9409 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -174,7 +174,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
     return 0;
 }
 
-static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
+static void tmp105_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     TMP105State *s = TMP105(i2c);
 
diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
index e9a6694..0b99643 100644
--- a/hw/nvram/Makefile.objs
+++ b/hw/nvram/Makefile.objs
@@ -1,5 +1,6 @@
 common-obj-$(CONFIG_DS1225Y) += ds1225y.o
 common-obj-y += eeprom93xx.o
+common-obj-y += at24.o
 common-obj-y += fw_cfg.o
 common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
 obj-$(CONFIG_PSERIES) += spapr_nvram.o
diff --git a/hw/nvram/at24.c b/hw/nvram/at24.c
new file mode 100644
index 0000000..7607a86
--- /dev/null
+++ b/hw/nvram/at24.c
@@ -0,0 +1,392 @@
+/*
+ * AT24Cxx EEPROM emulation
+ *
+ * Copyright (c) Siemens AG, 2012, 2013
+ * Author: Jan Kiszka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/block/block.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
+
+#define TYPE_AT24 "at24"
+#define AT24(obj) OBJECT_CHECK(AT24State, (obj), TYPE_AT24)
+
+#define AT24_BASE_ADDRESS   0x50
+#define AT24_MAX_PAGE_LEN   256
+
+typedef struct AT24Parameters {
+    const char *desc;
+    unsigned int size;
+    unsigned int page_size;
+    unsigned int device_bits;
+    unsigned int hi_addr_bits;
+    bool addr16;
+} AT24Parameters;
+
+typedef enum AT24TransferState {
+    AT24_IDLE,
+    AT24_RD_ADDR,
+    AT24_WR_ADDR_HI,
+    AT24_WR_ADDR_LO,
+    AT24_RW_DATA0,
+    AT24_RD_DATA,
+    AT24_WR_DATA,
+} AT24TransferState;
+
+typedef struct AT24State {
+    I2CSlave parent_obj;
+
+    BlockConf block_conf;
+    BlockBackend *blk;
+    bool wp;
+    unsigned int addr_mask;
+    unsigned int page_mask;
+    bool addr16;
+    unsigned int hi_addr_mask;
+    uint8_t device;
+    AT24TransferState transfer_state;
+    uint8_t sector_buffer[BDRV_SECTOR_SIZE];
+    int cached_sector;
+    bool cache_dirty;
+    uint32_t transfer_addr;
+} AT24State;
+
+static void at24_flush_transfer_buffer(AT24State *s)
+{
+    if (s->cached_sector < 0 || !s->cache_dirty) {
+        return;
+    }
+    blk_pwrite(s->blk, s->cached_sector, s->sector_buffer, 1);
+    s->cache_dirty = false;
+}
+
+static void at24_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
+{
+    AT24State *s = AT24(i2c);
+
+    switch (event) {
+    case I2C_START_SEND:
+        switch (s->transfer_state) {
+        case AT24_IDLE:
+            if (s->addr16) {
+                s->transfer_addr = (param & s->hi_addr_mask) << 16;
+                s->transfer_state = AT24_WR_ADDR_HI;
+            } else {
+                s->transfer_addr = (param & s->hi_addr_mask) << 8;
+                s->transfer_state = AT24_WR_ADDR_LO;
+            }
+            break;
+        default:
+            s->transfer_state = AT24_IDLE;
+            break;
+        }
+        break;
+    case I2C_START_RECV:
+        switch (s->transfer_state) {
+        case AT24_IDLE:
+            s->transfer_state = AT24_RD_ADDR;
+            break;
+        case AT24_RW_DATA0:
+            s->transfer_state = AT24_RD_DATA;
+            break;
+        default:
+            s->transfer_state = AT24_IDLE;
+            break;
+        }
+        break;
+    case I2C_FINISH:
+        switch (s->transfer_state) {
+        case AT24_WR_DATA:
+            at24_flush_transfer_buffer(s);
+            /* fall through */
+        default:
+            s->transfer_state = AT24_IDLE;
+            break;
+        }
+        break;
+    default:
+        s->transfer_state = AT24_IDLE;
+        break;
+    }
+}
+
+static int at24_cache_sector(AT24State *s, int sector)
+{
+    int ret;
+
+    if (s->cached_sector == sector) {
+        return 0;
+    }
+    ret = blk_pread(s->blk, sector, s->sector_buffer, 1);
+    if (ret < 0) {
+        s->cached_sector = -1;
+        return ret;
+    }
+    s->cached_sector = sector;
+    s->cache_dirty = false;
+    return 0;
+}
+
+static int at24_tx(I2CSlave *i2c, uint8_t data)
+{
+    AT24State *s = AT24(i2c);
+
+    switch (s->transfer_state) {
+    case AT24_WR_ADDR_HI:
+        s->transfer_addr |= (data << 8) & s->addr_mask;
+        s->transfer_state = AT24_WR_ADDR_LO;
+        break;
+    case AT24_WR_ADDR_LO:
+        s->transfer_addr |= data & s->addr_mask;
+        s->transfer_state = AT24_RW_DATA0;
+        break;
+    case AT24_RW_DATA0:
+        s->transfer_state = AT24_WR_DATA;
+        if (at24_cache_sector(s, s->transfer_addr >> BDRV_SECTOR_BITS) < 0) {
+            s->transfer_state = AT24_IDLE;
+            return -1;
+        }
+        /* fall through */
+    case AT24_WR_DATA:
+        if (!s->wp) {
+            s->sector_buffer[s->transfer_addr & ~BDRV_SECTOR_MASK] = data;
+            s->cache_dirty = true;
+        }
+        s->transfer_addr = (s->transfer_addr & s->page_mask) |
+            ((s->transfer_addr + 1) & ~s->page_mask);
+        break;
+    default:
+        s->transfer_state = AT24_IDLE;
+        return -1;
+    }
+    return 0;
+}
+
+static int at24_rx(I2CSlave *i2c)
+{
+    AT24State *s = AT24(i2c);
+    unsigned int sector, offset;
+    int result;
+
+    switch (s->transfer_state) {
+    case AT24_RD_ADDR:
+        s->transfer_state = AT24_IDLE;
+        result = s->transfer_addr;
+        break;
+    case AT24_RD_DATA:
+        sector = s->transfer_addr >> BDRV_SECTOR_BITS;
+        offset = s->transfer_addr & ~BDRV_SECTOR_MASK;
+        s->transfer_addr = (s->transfer_addr + 1) & s->addr_mask;
+        if (at24_cache_sector(s, sector) < 0) {
+            result = 0;
+            break;
+        }
+        result = s->sector_buffer[offset];
+        break;
+    default:
+        s->transfer_state = AT24_IDLE;
+        result = 0;
+        break;
+    }
+    return result;
+}
+
+static void at24_reset(DeviceState *d)
+{
+    AT24State *s = AT24(d);
+
+    s->transfer_state = AT24_IDLE;
+    s->cached_sector = -1;
+}
+
+static const AT24Parameters at24_parameters[] = {
+    { "AT24C1 EEPROM",       1*1024,   8, 3, 0, false },
+    { "AT24C2 EEPROM",       2*1024,   8, 3, 0, false },
+    { "AT24C4 EEPROM",       4*1024,  16, 2, 1, false },
+    { "AT24C8 EEPROM",       8*1024,  16, 1, 2, false },
+    { "AT24C16 EEPROM",     16*1024,  16, 0, 3, false },
+    { "AT24C32 EEPROM",     32*1024,  32, 3, 0, true },
+    { "AT24C62 EEPROM",     64*1024,  32, 3, 0, true },
+    { "AT24C128 EEPROM",   128*1024,  64, 2, 0, true },
+    { "AT24C256 EEPROM",   256*1024,  64, 2, 0, true },
+    { "AT24C512 EEPROM",   512*1024, 128, 2, 0, true },
+    { "AT24C1024 EEPROM", 1024*1024, 256, 1, 1, true },
+    { },
+};
+
+static void at24_realize(DeviceState *d, Error **errp)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(d);
+    I2CSlave *i2c = I2C_SLAVE(d);
+    AT24State *s = AT24(d);
+    const AT24Parameters *params;
+    int64_t image_size;
+    uint32_t size;
+    int dev_no;
+
+    s->blk = s->block_conf.blk;
+    if (!s->blk) {
+        error_setg(errp, "drive property not set");
+        return;
+    }
+
+    s->wp = blk_is_read_only(s->blk);
+
+    image_size = blk_getlength(s->blk);
+
+    for (params = at24_parameters; params->size != 0; params++) {
+        if (params->desc == dc->desc) {
+            break;
+        }
+    }
+    size = params->size / 8;
+
+    if (size == 0) {
+        size = image_size;
+
+        for (params = at24_parameters; params->size != 0; params++) {
+            if (size * 8 == params->size) {
+                break;
+            }
+        }
+        if (params->size == 0) {
+            error_setg(errp, "invalid EEPROM size, must be 2^(10..17)");
+            return;
+        }
+    } else if (image_size < size) {
+        error_setg(errp, "image file smaller than EEPROM size");
+        return;
+    }
+
+    s->addr_mask = size - 1;
+    s->page_mask = ~(params->page_size - 1);
+    s->hi_addr_mask = (1 << params->hi_addr_bits) - 1;
+    s->addr16 = params->addr16;
+
+    dev_no = (s->device & ((1 << params->device_bits) - 1)) <<
+        params->hi_addr_bits;
+    i2c_set_slave_address(i2c, AT24_BASE_ADDRESS | dev_no);
+    i2c_set_slave_address_mask(i2c, 0x7f & ~s->hi_addr_mask);
+}
+
+static void at24_pre_save(void *opaque)
+{
+    AT24State *s = opaque;
+
+    at24_flush_transfer_buffer(s);
+}
+
+static int at24_post_load(void *opaque, int version_id)
+{
+    AT24State *s = opaque;
+
+    s->cached_sector = -1;
+    return 0;
+}
+
+static const VMStateDescription vmstate_at24 = {
+    .name = "at24",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = at24_pre_save,
+    .post_load = at24_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(transfer_state, AT24State),
+        VMSTATE_UINT32(transfer_addr, AT24State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property at24_properties[] = {
+    DEFINE_BLOCK_PROPERTIES(AT24State, block_conf),
+    DEFINE_PROP_UINT8("device", AT24State, device, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void at24_base_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->event = at24_event;
+    sc->recv = at24_rx;
+    sc->send = at24_tx;
+    dc->desc = "AT24Cxx EEPROM (defined by image size)";
+    dc->reset = at24_reset;
+    dc->realize = at24_realize;
+    dc->vmsd = &vmstate_at24;
+    dc->props = at24_properties;
+}
+
+static void at24cxx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    const AT24Parameters *params = data;
+
+    dc->desc = params->desc;
+}
+
+#define AT24CXX_TYPE_INFO(type_name, param_no) \
+    { \
+        .name          = (type_name), \
+        .parent        = TYPE_AT24, \
+        .instance_size = sizeof(AT24State), \
+        .class_init    = at24cxx_class_init, \
+        .class_data    = (void *)&at24_parameters[(param_no)], \
+    }
+
+static const TypeInfo at24_info[] = {
+    {
+        .name          = "at24",
+        .parent        = TYPE_I2C_SLAVE,
+        .instance_size = sizeof(AT24State),
+        .class_init    = at24_base_class_init,
+    },
+    AT24CXX_TYPE_INFO("at24c1",     0),
+    AT24CXX_TYPE_INFO("at24c2",     1),
+    AT24CXX_TYPE_INFO("at24c4",     2),
+    AT24CXX_TYPE_INFO("at24c8",     3),
+    AT24CXX_TYPE_INFO("at24c16",    4),
+    AT24CXX_TYPE_INFO("at24c32",    5),
+    AT24CXX_TYPE_INFO("at24c64",    6),
+    AT24CXX_TYPE_INFO("at24c128",   7),
+    AT24CXX_TYPE_INFO("at24c256",   8),
+    AT24CXX_TYPE_INFO("at24c512",   9),
+    AT24CXX_TYPE_INFO("at24c1024", 10),
+};
+
+static void at24_register_types(void)
+{
+    unsigned int n;
+
+    /* buffering is based on this, enforce it early */
+    assert(AT24_MAX_PAGE_LEN <= BDRV_SECTOR_SIZE);
+
+    for (n = 0; n < ARRAY_SIZE(at24_info); n++) {
+        type_register_static(&at24_info[n]);
+    }
+}
+
+type_init(at24_register_types)
diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index ec6dbee..20cc792 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -91,7 +91,7 @@ static void inc_regptr(DS1338State *s)
     }
 }
 
-static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
+static void ds1338_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     DS1338State *s = DS1338(i2c);
 
diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c
index 7ded4ba..b63853e 100644
--- a/hw/timer/twl92230.c
+++ b/hw/timer/twl92230.c
@@ -711,7 +711,7 @@ static void menelaus_write(void *opaque, uint8_t addr, 
uint8_t value)
     }
 }
 
-static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
+static void menelaus_event(I2CSlave *i2c, enum i2c_event event, uint8_t param)
 {
     MenelausState *s = TWL92230(i2c);
 
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 4986ebc..180d83b 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -39,7 +39,7 @@ typedef struct I2CSlaveClass
     int (*recv)(I2CSlave *s);
 
     /* Notify the slave of a bus state change.  */
-    void (*event)(I2CSlave *s, enum i2c_event event);
+    void (*event)(I2CSlave *s, enum i2c_event event, uint8_t param);
 } I2CSlaveClass;
 
 struct I2CSlave
@@ -48,10 +48,12 @@ struct I2CSlave
 
     /* Remaining fields for internal use by the I2C code.  */
     uint8_t address;
+    uint8_t address_mask;
 };
 
 I2CBus *i2c_init_bus(DeviceState *parent, const char *name);
 void i2c_set_slave_address(I2CSlave *dev, uint8_t address);
+void i2c_set_slave_address_mask(I2CSlave *dev, uint8_t mask);
 int i2c_bus_busy(I2CBus *bus);
 int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv);
 void i2c_end_transfer(I2CBus *bus);
-- 
1.9.1


Hottinger Baldwin Messtechnik GmbH, Im Tiefen See 45, 64293 Darmstadt, Germany 
| www.hbm.com 

Registered as GmbH (German limited liability corporation) in the commercial 
register at the local court of Darmstadt, HRB 1147  
Company domiciled in Darmstadt | Managing Director: Andreas Huellhorst | 
Chairman of the board: Eoghan O'Lionaird

Als Gesellschaft mit beschraenkter Haftung eingetragen im Handelsregister des 
Amtsgerichts Darmstadt unter HRB 1147 
Sitz der Gesellschaft: Darmstadt | Geschaeftsfuehrung: Andreas Huellhorst | 
Aufsichtsratsvorsitzender: Eoghan O'Lionaird

The information in this email is confidential. It is intended solely for the 
addressee. If you are not the intended recipient, please let me know and delete 
this email.

Die in dieser E-Mail enthaltene Information ist vertraulich und lediglich fuer 
den Empfaenger bestimmt. Sollten Sie nicht der eigentliche Empfaenger sein, 
informieren Sie mich bitte kurz und loeschen diese E-Mail.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]