From 1ea96673c611cdc05ea32ac81f40d9f864e18507 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Thu, 14 May 2009 22:35:08 +0100 Subject: SMBus qdev conversion Signed-off-by: Paul Brook --- hw/mips_malta.c | 6 +++++- hw/pc.c | 6 +++++- hw/smbus.c | 58 ++++++++++++++++++++++++++++++++----------------------- hw/smbus.h | 25 ++++++++++++------------ hw/smbus_eeprom.c | 34 ++++++++++++++++++++------------ 5 files changed, 78 insertions(+), 51 deletions(-) (limited to 'hw') diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 9710adc..747143d 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -911,7 +911,11 @@ void mips_malta_init (ram_addr_t ram_size, eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ for (i = 0; i < 8; i++) { /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); + DeviceState *eeprom; + eeprom = qdev_create(smbus, "smbus-eeprom"); + qdev_set_prop_int(eeprom, "address", 0x50 + i); + qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256)); + qdev_init(eeprom); } pit = pit_init(0x40, i8259[0]); DMA_init(0); diff --git a/hw/pc.c b/hw/pc.c index e227a22..c07e7fa 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1109,7 +1109,11 @@ static void pc_init1(ram_addr_t ram_size, /* TODO: Populate SPD eeprom data. */ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]); for (i = 0; i < 8; i++) { - smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); + DeviceState *eeprom; + eeprom = qdev_create(smbus, "smbus-eeprom"); + qdev_set_prop_int(eeprom, "address", 0x50 + i); + qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256)); + qdev_init(eeprom); } } diff --git a/hw/smbus.c b/hw/smbus.c index 222c3fd..6bea4fa 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -37,33 +37,38 @@ enum { static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) { + SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c); + DPRINTF("Quick Command %d\n", recv); - if (dev->quick_cmd) - dev->quick_cmd(dev, recv); + if (t->quick_cmd) + t->quick_cmd(dev, recv); } static void smbus_do_write(SMBusDevice *dev) { + SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c); + if (dev->data_len == 0) { smbus_do_quick_cmd(dev, 0); } else if (dev->data_len == 1) { DPRINTF("Send Byte\n"); - if (dev->send_byte) { - dev->send_byte(dev, dev->data_buf[0]); + if (t->send_byte) { + t->send_byte(dev, dev->data_buf[0]); } } else { dev->command = dev->data_buf[0]; DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); - if (dev->write_data) { - dev->write_data(dev, dev->command, dev->data_buf + 1, - dev->data_len - 1); + if (t->write_data) { + t->write_data(dev, dev->command, dev->data_buf + 1, + dev->data_len - 1); } } } static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) { - SMBusDevice *dev = (SMBusDevice *)s; + SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); + switch (event) { case I2C_START_SEND: switch (dev->mode) { @@ -145,13 +150,14 @@ static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) static int smbus_i2c_recv(i2c_slave *s) { - SMBusDevice *dev = (SMBusDevice *)s; + SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c); + SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); int ret; switch (dev->mode) { case SMBUS_RECV_BYTE: - if (dev->receive_byte) { - ret = dev->receive_byte(dev); + if (t->receive_byte) { + ret = t->receive_byte(dev); } else { ret = 0; } @@ -159,8 +165,8 @@ static int smbus_i2c_recv(i2c_slave *s) dev->mode = SMBUS_DONE; break; case SMBUS_READ_DATA: - if (dev->read_data) { - ret = dev->read_data(dev, dev->command, dev->data_len); + if (t->read_data) { + ret = t->read_data(dev, dev->command, dev->data_len); dev->data_len++; } else { ret = 0; @@ -178,7 +184,8 @@ static int smbus_i2c_recv(i2c_slave *s) static int smbus_i2c_send(i2c_slave *s, uint8_t data) { - SMBusDevice *dev = (SMBusDevice *)s; + SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); + switch (dev->mode) { case SMBUS_WRITE_DATA: DPRINTF("Write data %02x\n", data); @@ -191,19 +198,22 @@ static int smbus_i2c_send(i2c_slave *s, uint8_t data) return 0; } -SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size) +static void smbus_device_init(i2c_slave *i2c) { - SMBusDevice *dev; + SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c); + SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c); - if (size < sizeof(SMBusDevice)) - hw_error("SMBus struct too small"); - - dev = (SMBusDevice *)i2c_slave_init(bus, address, size); - dev->i2c.event = smbus_i2c_event; - dev->i2c.recv = smbus_i2c_recv; - dev->i2c.send = smbus_i2c_send; + t->init(dev); +} - return dev; +void smbus_register_device(const char *name, int size, SMBusDeviceInfo *info) +{ + assert(size >= sizeof(SMBusDevice)); + info->i2c.init = smbus_device_init; + info->i2c.event = smbus_i2c_event; + info->i2c.recv = smbus_i2c_recv; + info->i2c.send = smbus_i2c_send; + i2c_register_slave(name, size, &info->i2c); } /* Master device commands. */ diff --git a/hw/smbus.h b/hw/smbus.h index 640377b..5b6e20f 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -28,7 +28,16 @@ struct SMBusDevice { /* The SMBus protocol is implemented on top of I2C. */ i2c_slave i2c; - /* Callbacks set by the device. */ + /* Remaining fields for internal use only. */ + int mode; + int data_len; + uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ + uint8_t command; +}; + +typedef struct { + I2CSlaveInfo i2c; + void (*init)(SMBusDevice *dev); void (*quick_cmd)(SMBusDevice *dev, uint8_t read); void (*send_byte)(SMBusDevice *dev, uint8_t val); uint8_t (*receive_byte)(SMBusDevice *dev); @@ -42,16 +51,9 @@ struct SMBusDevice { byte at a time. The device is responsible for adding the length byte on block reads. */ uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n); +} SMBusDeviceInfo; - /* Remaining fields for internal use only. */ - int mode; - int data_len; - uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ - uint8_t command; -}; - -/* Create a slave device. */ -SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size); +void smbus_register_device(const char *name, int size, SMBusDeviceInfo *info); /* Master device commands. */ void smbus_quick_command(i2c_bus *bus, int addr, int read); @@ -64,6 +66,3 @@ void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data); int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data); void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data, int len); - -/* smbus_eeprom.c */ -void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf); diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index ce5f5f2..3f8b386 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -29,7 +29,7 @@ //#define DEBUG typedef struct SMBusEEPROMDevice { - SMBusDevice dev; + SMBusDevice smbusdev; uint8_t *data; uint8_t offset; } SMBusEEPROMDevice; @@ -95,18 +95,28 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) return eeprom_receive_byte(dev); } -void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf) +static void smbus_eeprom_init(SMBusDevice *dev) { - SMBusEEPROMDevice *eeprom; + SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; - eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr, - sizeof(SMBusEEPROMDevice)); - - eeprom->dev.quick_cmd = eeprom_quick_cmd; - eeprom->dev.send_byte = eeprom_send_byte; - eeprom->dev.receive_byte = eeprom_receive_byte; - eeprom->dev.write_data = eeprom_write_data; - eeprom->dev.read_data = eeprom_read_data; - eeprom->data = buf; + /* FIXME: Should be a blob rather than a ptr. */ + eeprom->data = qdev_get_prop_ptr(&dev->i2c.qdev, "data"); eeprom->offset = 0; } + +static SMBusDeviceInfo smbus_eeprom_info = { + .init = smbus_eeprom_init, + .quick_cmd = eeprom_quick_cmd, + .send_byte = eeprom_send_byte, + .receive_byte = eeprom_receive_byte, + .write_data = eeprom_write_data, + .read_data = eeprom_read_data +}; + +static void smbus_eeprom_register_devices(void) +{ + smbus_register_device("smbus-eeprom", sizeof(SMBusEEPROMDevice), + &smbus_eeprom_info); +} + +device_init(smbus_eeprom_register_devices) -- cgit v1.1