mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/cminyard/tags/i2c-for-release-20190228' into staging
This has been out there long enough, I need to get this in.
This was changed a little bit since my post on Feb 20 (to which
there were no comments) due to changes I had to work around:
Change b296b664ab "smbus: Add a helper to generate SPD EEPROM
data" added a function to include/hw/i2c/smbus.h, which I had to move to
include/hw/smbus_eeprom.h.
There were some changes to hw/i2c/Makefile.objs that I had to fix up.
Beyond that, no changes.
Thanks,
-corey
# gpg: Signature made Thu 28 Feb 2019 18:05:49 GMT
# gpg: using RSA key FD0D5CE67CE0F59A6688268661F38C90919BFF81
# gpg: Good signature from "Corey Minyard <cminyard@mvista.com>" [unknown]
# gpg: aka "Corey Minyard <minyard@acm.org>" [unknown]
# gpg: aka "Corey Minyard <corey@minyard.net>" [unknown]
# gpg: aka "Corey Minyard <minyard@mvista.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: FD0D 5CE6 7CE0 F59A 6688 2686 61F3 8C90 919B FF81
* remotes/cminyard/tags/i2c-for-release-20190228:
i2c: Verify that the count passed in to smbus_eeprom_init() is valid
i2c:smbus_eeprom: Add a reset function to smbus_eeprom
i2c:smbus_eeprom: Add vmstate handling to the smbus eeprom
i2c:smbus_eeprom: Add a size constant for the smbus_eeprom size
i2c:smbus_eeprom: Add normal type name and cast to smbus_eeprom.c
i2c:smbus_slave: Add an SMBus vmstate structure
i2c:pm_smbus: Fix state transfer
migration: Add a VMSTATE_BOOL_TEST() macro
i2c:pm_smbus: Fix pm_smbus handling of I2C block read
boards.h: Ignore migration for SMBus devices on older machines
i2c:smbus: Make white space in switch statements consistent
i2c:smbus_eeprom: Get rid of the quick command
i2c:smbus: Simplify read handling
i2c:smbus: Simplify write operation
i2c:smbus: Correct the working of quick commands
i2c: Don't check return value from i2c_recv()
arm:i2c: Don't mask return from i2c_recv()
i2c: have I2C receive operation return uint8_t
i2c: Split smbus into parts
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+12
@@ -2192,6 +2192,18 @@ M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
|
||||
S: Maintained
|
||||
F: contrib/elf2dmp/
|
||||
|
||||
I2C and SMBus
|
||||
M: Corey Minyard <cminyard@mvista.com>
|
||||
S: Maintained
|
||||
F: hw/i2c/core.c
|
||||
F: hw/i2c/smbus_slave.c
|
||||
F: hw/i2c/smbus_master.c
|
||||
F: hw/i2c/smbus_eeprom.c
|
||||
F: include/hw/i2c/i2c.h
|
||||
F: include/hw/i2c/smbus_master.h
|
||||
F: include/hw/i2c/smbus_slave.h
|
||||
F: include/hw/i2c/smbus_eeprom.h
|
||||
|
||||
Usermode Emulation
|
||||
------------------
|
||||
Overall
|
||||
|
||||
@@ -302,6 +302,11 @@ static const VMStateDescription vmstate_cpuhp_state = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool piix4_vmstate_need_smbus(void *opaque, int version_id)
|
||||
{
|
||||
return pm_smbus_vmstate_needed();
|
||||
}
|
||||
|
||||
/* qemu-kvm 1.2 uses version 3 but advertised as 2
|
||||
* To support incoming qemu-kvm 1.2 migration, change version_id
|
||||
* and minimum_version_id to 2 below (which breaks migration from
|
||||
@@ -321,6 +326,8 @@ static const VMStateDescription vmstate_acpi = {
|
||||
VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
|
||||
VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
|
||||
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
|
||||
VMSTATE_STRUCT_TEST(smb, PIIX4PMState, piix4_vmstate_need_smbus, 3,
|
||||
pmsmb_vmstate, PMSMBus),
|
||||
VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
|
||||
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
|
||||
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
#include "hw/arm/aspeed.h"
|
||||
#include "hw/arm/aspeed_soc.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
+1
-1
@@ -1286,7 +1286,7 @@ static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
||||
static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
|
||||
{
|
||||
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||
PXA2xxI2CState *s = slave->host;
|
||||
|
||||
+1
-1
@@ -811,7 +811,7 @@ static void stellaris_i2c_write(void *opaque, hwaddr offset,
|
||||
/* TODO: Handle errors. */
|
||||
if (s->msa & 1) {
|
||||
/* Recv */
|
||||
s->mdr = i2c_recv(s->bus) & 0xff;
|
||||
s->mdr = i2c_recv(s->bus);
|
||||
} else {
|
||||
/* Send */
|
||||
i2c_send(s->bus, s->mdr);
|
||||
|
||||
+2
-2
@@ -197,10 +197,10 @@ static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tosa_dac_recv(I2CSlave *s)
|
||||
static uint8_t tosa_dac_recv(I2CSlave *s)
|
||||
{
|
||||
printf("%s: recv not supported!!!\n", __func__);
|
||||
return -1;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void tosa_tg_init(PXA2xxState *cpu)
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aer915_recv(I2CSlave *slave)
|
||||
static uint8_t aer915_recv(I2CSlave *slave)
|
||||
{
|
||||
AER915State *s = AER915(slave);
|
||||
int retval = 0x00;
|
||||
|
||||
+1
-1
@@ -561,7 +561,7 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8750_rx(I2CSlave *i2c)
|
||||
static uint8_t wm8750_rx(I2CSlave *i2c)
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sii9022_rx(I2CSlave *i2c)
|
||||
static uint8_t sii9022_rx(I2CSlave *i2c)
|
||||
{
|
||||
sii9022_state *s = SII9022(i2c);
|
||||
uint8_t res = 0x00;
|
||||
|
||||
@@ -62,10 +62,10 @@ typedef struct {
|
||||
uint8_t framebuffer[132*8];
|
||||
} ssd0303_state;
|
||||
|
||||
static int ssd0303_recv(I2CSlave *i2c)
|
||||
static uint8_t ssd0303_recv(I2CSlave *i2c)
|
||||
{
|
||||
BADF("Reads not implemented\n");
|
||||
return -1;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static int ssd0303_send(I2CSlave *i2c, uint8_t data)
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ static void max7310_reset(DeviceState *dev)
|
||||
s->command = 0x00;
|
||||
}
|
||||
|
||||
static int max7310_rx(I2CSlave *i2c)
|
||||
static uint8_t max7310_rx(I2CSlave *i2c)
|
||||
{
|
||||
MAX7310State *s = MAX7310(i2c);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
common-obj-$(CONFIG_I2C) += core.o smbus.o
|
||||
common-obj-$(CONFIG_I2C) += core.o smbus_slave.o smbus_master.o
|
||||
common-obj-$(CONFIG_SMBUS_EEPROM) += smbus_eeprom.o
|
||||
common-obj-$(CONFIG_DDC) += i2c-ddc.o
|
||||
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
|
||||
|
||||
+2
-7
@@ -189,16 +189,11 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
|
||||
|
||||
static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
|
||||
{
|
||||
int ret;
|
||||
uint8_t ret;
|
||||
|
||||
aspeed_i2c_set_state(bus, I2CD_MRXD);
|
||||
ret = i2c_recv(bus->bus);
|
||||
if (ret < 0) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__);
|
||||
ret = 0xff;
|
||||
} else {
|
||||
bus->intr_status |= I2CD_INTR_RX_DONE;
|
||||
}
|
||||
bus->intr_status |= I2CD_INTR_RX_DONE;
|
||||
bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
|
||||
if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
|
||||
i2c_nack(bus->bus);
|
||||
|
||||
+13
-19
@@ -191,23 +191,17 @@ int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
|
||||
}
|
||||
return ret ? -1 : 0;
|
||||
} else {
|
||||
if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
|
||||
if (sc->recv) {
|
||||
s = QLIST_FIRST(&bus->current_devs)->elt;
|
||||
ret = sc->recv(s);
|
||||
trace_i2c_recv(s->address, ret);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else {
|
||||
*data = ret;
|
||||
return 0;
|
||||
ret = 0xff;
|
||||
if (!QLIST_EMPTY(&bus->current_devs) && !bus->broadcast) {
|
||||
sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
|
||||
if (sc->recv) {
|
||||
s = QLIST_FIRST(&bus->current_devs)->elt;
|
||||
ret = sc->recv(s);
|
||||
trace_i2c_recv(s->address, ret);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
*data = ret;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,12 +210,12 @@ int i2c_send(I2CBus *bus, uint8_t data)
|
||||
return i2c_send_recv(bus, &data, true);
|
||||
}
|
||||
|
||||
int i2c_recv(I2CBus *bus)
|
||||
uint8_t i2c_recv(I2CBus *bus)
|
||||
{
|
||||
uint8_t data;
|
||||
int ret = i2c_send_recv(bus, &data, false);
|
||||
uint8_t data = 0xff;
|
||||
|
||||
return ret < 0 ? ret : data;
|
||||
i2c_send_recv(bus, &data, false);
|
||||
return data;
|
||||
}
|
||||
|
||||
void i2c_nack(I2CBus *bus)
|
||||
|
||||
@@ -106,16 +106,10 @@ static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
|
||||
static void exynos4210_i2c_data_receive(void *opaque)
|
||||
{
|
||||
Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
|
||||
int ret;
|
||||
|
||||
s->i2cstat &= ~I2CSTAT_LAST_BIT;
|
||||
s->scl_free = false;
|
||||
ret = i2c_recv(s->bus);
|
||||
if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
|
||||
s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */
|
||||
} else {
|
||||
s->i2cds = ret;
|
||||
}
|
||||
s->i2cds = i2c_recv(s->bus);
|
||||
exynos4210_i2c_raise_interrupt(s);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_ddc_rx(I2CSlave *i2c)
|
||||
static uint8_t i2c_ddc_rx(I2CSlave *i2c)
|
||||
{
|
||||
I2CDDCState *s = I2CDDC(i2c);
|
||||
|
||||
|
||||
+2
-10
@@ -120,7 +120,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
|
||||
value = s->i2dr_read;
|
||||
|
||||
if (imx_i2c_is_master(s)) {
|
||||
int ret = 0xff;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (s->address == ADDR_RESET) {
|
||||
/* something is wrong as the address is not set */
|
||||
@@ -133,15 +133,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
|
||||
} else {
|
||||
/* get the next byte */
|
||||
ret = i2c_recv(s->bus);
|
||||
|
||||
if (ret >= 0) {
|
||||
imx_i2c_raise_interrupt(s);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed "
|
||||
"for device 0x%02x\n", TYPE_IMX_I2C,
|
||||
__func__, s->address);
|
||||
ret = 0xff;
|
||||
}
|
||||
imx_i2c_raise_interrupt(s);
|
||||
}
|
||||
|
||||
s->i2dr_read = ret;
|
||||
|
||||
+99
-20
@@ -19,8 +19,9 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/pm_smbus.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "hw/i2c/smbus_master.h"
|
||||
|
||||
#define SMBHSTSTS 0x00
|
||||
#define SMBHSTCNT 0x02
|
||||
@@ -118,19 +119,30 @@ static void smb_transaction(PMSMBus *s)
|
||||
}
|
||||
break;
|
||||
case PROT_I2C_BLOCK_READ:
|
||||
if (read) {
|
||||
int xfersize = s->smb_data0;
|
||||
if (xfersize > sizeof(s->smb_data)) {
|
||||
xfersize = sizeof(s->smb_data);
|
||||
}
|
||||
ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data,
|
||||
xfersize, false, true);
|
||||
goto data8;
|
||||
} else {
|
||||
/* The manual says the behavior is undefined, just set DEV_ERR. */
|
||||
/* According to the Linux i2c-i801 driver:
|
||||
* NB: page 240 of ICH5 datasheet shows that the R/#W
|
||||
* bit should be cleared here, even when reading.
|
||||
* However if SPD Write Disable is set (Lynx Point and later),
|
||||
* the read will fail if we don't set the R/#W bit.
|
||||
* So at least Linux may or may not set the read bit here.
|
||||
* So just ignore the read bit for this command.
|
||||
*/
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
ret = i2c_send(bus, s->smb_data1);
|
||||
if (ret) {
|
||||
goto error;
|
||||
}
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
goto error;
|
||||
}
|
||||
s->in_i2c_block_read = true;
|
||||
s->smb_blkdata = i2c_recv(s->smbus);
|
||||
s->op_done = false;
|
||||
s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
|
||||
goto out;
|
||||
|
||||
case PROT_BLOCK_DATA:
|
||||
if (read) {
|
||||
ret = smbus_read_block(bus, addr, cmd, s->smb_data,
|
||||
@@ -208,6 +220,7 @@ static void smb_transaction_start(PMSMBus *s)
|
||||
{
|
||||
if (s->smb_ctl & CTL_INTREN) {
|
||||
smb_transaction(s);
|
||||
s->start_transaction_on_status_read = false;
|
||||
} else {
|
||||
/* Do not execute immediately the command; it will be
|
||||
* executed when guest will read SMB_STAT register. This
|
||||
@@ -217,6 +230,7 @@ static void smb_transaction_start(PMSMBus *s)
|
||||
* checking for status. If STS_HOST_BUSY doesn't get
|
||||
* set, it gets stuck. */
|
||||
s->smb_stat |= STS_HOST_BUSY;
|
||||
s->start_transaction_on_status_read = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,19 +240,38 @@ smb_irq_value(PMSMBus *s)
|
||||
return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
|
||||
}
|
||||
|
||||
static bool
|
||||
smb_byte_by_byte(PMSMBus *s)
|
||||
{
|
||||
if (s->op_done) {
|
||||
return false;
|
||||
}
|
||||
if (s->in_i2c_block_read) {
|
||||
return true;
|
||||
}
|
||||
return !(s->smb_auxctl & AUX_BLK);
|
||||
}
|
||||
|
||||
static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned width)
|
||||
{
|
||||
PMSMBus *s = opaque;
|
||||
uint8_t clear_byte_done;
|
||||
|
||||
SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx
|
||||
" val=0x%02" PRIx64 "\n", addr, val);
|
||||
switch(addr) {
|
||||
case SMBHSTSTS:
|
||||
clear_byte_done = s->smb_stat & val & STS_BYTE_DONE;
|
||||
s->smb_stat &= ~(val & ~STS_HOST_BUSY);
|
||||
if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
|
||||
if (clear_byte_done && smb_byte_by_byte(s)) {
|
||||
uint8_t read = s->smb_addr & 0x01;
|
||||
|
||||
if (s->in_i2c_block_read) {
|
||||
/* See comment below PROT_I2C_BLOCK_READ above. */
|
||||
read = 1;
|
||||
}
|
||||
|
||||
s->smb_index++;
|
||||
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
|
||||
s->smb_index = 0;
|
||||
@@ -268,12 +301,23 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
|
||||
s->smb_stat |= STS_BYTE_DONE;
|
||||
} else if (s->smb_ctl & CTL_LAST_BYTE) {
|
||||
s->op_done = true;
|
||||
s->smb_blkdata = s->smb_data[s->smb_index];
|
||||
if (s->in_i2c_block_read) {
|
||||
s->in_i2c_block_read = false;
|
||||
s->smb_blkdata = i2c_recv(s->smbus);
|
||||
i2c_nack(s->smbus);
|
||||
i2c_end_transfer(s->smbus);
|
||||
} else {
|
||||
s->smb_blkdata = s->smb_data[s->smb_index];
|
||||
}
|
||||
s->smb_index = 0;
|
||||
s->smb_stat |= STS_INTR;
|
||||
s->smb_stat &= ~STS_HOST_BUSY;
|
||||
} else {
|
||||
s->smb_blkdata = s->smb_data[s->smb_index];
|
||||
if (s->in_i2c_block_read) {
|
||||
s->smb_blkdata = i2c_recv(s->smbus);
|
||||
} else {
|
||||
s->smb_blkdata = s->smb_data[s->smb_index];
|
||||
}
|
||||
s->smb_stat |= STS_BYTE_DONE;
|
||||
}
|
||||
}
|
||||
@@ -284,6 +328,10 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
|
||||
if (!s->op_done) {
|
||||
s->smb_index = 0;
|
||||
s->op_done = true;
|
||||
if (s->in_i2c_block_read) {
|
||||
s->in_i2c_block_read = false;
|
||||
i2c_end_transfer(s->smbus);
|
||||
}
|
||||
}
|
||||
smb_transaction_start(s);
|
||||
}
|
||||
@@ -337,8 +385,9 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
|
||||
switch(addr) {
|
||||
case SMBHSTSTS:
|
||||
val = s->smb_stat;
|
||||
if (s->smb_stat & STS_HOST_BUSY) {
|
||||
if (s->start_transaction_on_status_read) {
|
||||
/* execute command now */
|
||||
s->start_transaction_on_status_read = false;
|
||||
s->smb_stat &= ~STS_HOST_BUSY;
|
||||
smb_transaction(s);
|
||||
}
|
||||
@@ -359,10 +408,10 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
|
||||
val = s->smb_data1;
|
||||
break;
|
||||
case SMBBLKDAT:
|
||||
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
|
||||
s->smb_index = 0;
|
||||
}
|
||||
if (s->smb_auxctl & AUX_BLK) {
|
||||
if (s->smb_auxctl & AUX_BLK && !s->in_i2c_block_read) {
|
||||
if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
|
||||
s->smb_index = 0;
|
||||
}
|
||||
val = s->smb_data[s->smb_index++];
|
||||
if (!s->op_done && s->smb_index == s->smb_data0) {
|
||||
s->op_done = true;
|
||||
@@ -405,6 +454,36 @@ static const MemoryRegionOps pm_smbus_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
bool pm_smbus_vmstate_needed(void)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
|
||||
return !mc->smbus_no_migration_support;
|
||||
}
|
||||
|
||||
const VMStateDescription pmsmb_vmstate = {
|
||||
.name = "pmsmb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(smb_stat, PMSMBus),
|
||||
VMSTATE_UINT8(smb_ctl, PMSMBus),
|
||||
VMSTATE_UINT8(smb_cmd, PMSMBus),
|
||||
VMSTATE_UINT8(smb_addr, PMSMBus),
|
||||
VMSTATE_UINT8(smb_data0, PMSMBus),
|
||||
VMSTATE_UINT8(smb_data1, PMSMBus),
|
||||
VMSTATE_UINT32(smb_index, PMSMBus),
|
||||
VMSTATE_UINT8_ARRAY(smb_data, PMSMBus, PM_SMBUS_MAX_MSG_SIZE),
|
||||
VMSTATE_UINT8(smb_auxctl, PMSMBus),
|
||||
VMSTATE_UINT8(smb_blkdata, PMSMBus),
|
||||
VMSTATE_BOOL(i2c_enable, PMSMBus),
|
||||
VMSTATE_BOOL(op_done, PMSMBus),
|
||||
VMSTATE_BOOL(in_i2c_block_read, PMSMBus),
|
||||
VMSTATE_BOOL(start_transaction_on_status_read, PMSMBus),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
|
||||
{
|
||||
smb->op_done = true;
|
||||
|
||||
-379
@@ -1,379 +0,0 @@
|
||||
/*
|
||||
* QEMU SMBus device emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licensed under the LGPL.
|
||||
*/
|
||||
|
||||
/* TODO: Implement PEC. */
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
|
||||
//#define DEBUG_SMBUS 1
|
||||
|
||||
#ifdef DEBUG_SMBUS
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
|
||||
#define BADF(fmt, ...) \
|
||||
do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do {} while(0)
|
||||
#define BADF(fmt, ...) \
|
||||
do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SMBUS_IDLE,
|
||||
SMBUS_WRITE_DATA,
|
||||
SMBUS_RECV_BYTE,
|
||||
SMBUS_READ_DATA,
|
||||
SMBUS_DONE,
|
||||
SMBUS_CONFUSED = -1
|
||||
};
|
||||
|
||||
static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
|
||||
{
|
||||
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
|
||||
|
||||
DPRINTF("Quick Command %d\n", recv);
|
||||
if (sc->quick_cmd) {
|
||||
sc->quick_cmd(dev, recv);
|
||||
}
|
||||
}
|
||||
|
||||
static void smbus_do_write(SMBusDevice *dev)
|
||||
{
|
||||
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (dev->data_len == 0) {
|
||||
smbus_do_quick_cmd(dev, 0);
|
||||
} else if (dev->data_len == 1) {
|
||||
DPRINTF("Send Byte\n");
|
||||
if (sc->send_byte) {
|
||||
sc->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 (sc->write_data) {
|
||||
sc->write_data(dev, dev->command, dev->data_buf + 1,
|
||||
dev->data_len - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
{
|
||||
SMBusDevice *dev = SMBUS_DEVICE(s);
|
||||
|
||||
switch (event) {
|
||||
case I2C_START_SEND:
|
||||
switch (dev->mode) {
|
||||
case SMBUS_IDLE:
|
||||
DPRINTF("Incoming data\n");
|
||||
dev->mode = SMBUS_WRITE_DATA;
|
||||
break;
|
||||
default:
|
||||
BADF("Unexpected send start condition in state %d\n", dev->mode);
|
||||
dev->mode = SMBUS_CONFUSED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_START_RECV:
|
||||
switch (dev->mode) {
|
||||
case SMBUS_IDLE:
|
||||
DPRINTF("Read mode\n");
|
||||
dev->mode = SMBUS_RECV_BYTE;
|
||||
break;
|
||||
case SMBUS_WRITE_DATA:
|
||||
if (dev->data_len == 0) {
|
||||
BADF("Read after write with no data\n");
|
||||
dev->mode = SMBUS_CONFUSED;
|
||||
} else {
|
||||
if (dev->data_len > 1) {
|
||||
smbus_do_write(dev);
|
||||
} else {
|
||||
dev->command = dev->data_buf[0];
|
||||
DPRINTF("%02x: Command %d\n", dev->i2c.address,
|
||||
dev->command);
|
||||
}
|
||||
DPRINTF("Read mode\n");
|
||||
dev->data_len = 0;
|
||||
dev->mode = SMBUS_READ_DATA;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BADF("Unexpected recv start condition in state %d\n", dev->mode);
|
||||
dev->mode = SMBUS_CONFUSED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_FINISH:
|
||||
switch (dev->mode) {
|
||||
case SMBUS_WRITE_DATA:
|
||||
smbus_do_write(dev);
|
||||
break;
|
||||
case SMBUS_RECV_BYTE:
|
||||
smbus_do_quick_cmd(dev, 1);
|
||||
break;
|
||||
case SMBUS_READ_DATA:
|
||||
BADF("Unexpected stop during receive\n");
|
||||
break;
|
||||
default:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
}
|
||||
dev->mode = SMBUS_IDLE;
|
||||
dev->data_len = 0;
|
||||
break;
|
||||
|
||||
case I2C_NACK:
|
||||
switch (dev->mode) {
|
||||
case SMBUS_DONE:
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
case SMBUS_READ_DATA:
|
||||
dev->mode = SMBUS_DONE;
|
||||
break;
|
||||
default:
|
||||
BADF("Unexpected NACK in state %d\n", dev->mode);
|
||||
dev->mode = SMBUS_CONFUSED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbus_i2c_recv(I2CSlave *s)
|
||||
{
|
||||
SMBusDevice *dev = SMBUS_DEVICE(s);
|
||||
SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
|
||||
int ret;
|
||||
|
||||
switch (dev->mode) {
|
||||
case SMBUS_RECV_BYTE:
|
||||
if (sc->receive_byte) {
|
||||
ret = sc->receive_byte(dev);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
DPRINTF("Receive Byte %02x\n", ret);
|
||||
dev->mode = SMBUS_DONE;
|
||||
break;
|
||||
case SMBUS_READ_DATA:
|
||||
if (sc->read_data) {
|
||||
ret = sc->read_data(dev, dev->command, dev->data_len);
|
||||
dev->data_len++;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
DPRINTF("Read data %02x\n", ret);
|
||||
break;
|
||||
default:
|
||||
BADF("Unexpected read in state %d\n", dev->mode);
|
||||
dev->mode = SMBUS_CONFUSED;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smbus_i2c_send(I2CSlave *s, uint8_t data)
|
||||
{
|
||||
SMBusDevice *dev = SMBUS_DEVICE(s);
|
||||
|
||||
switch (dev->mode) {
|
||||
case SMBUS_WRITE_DATA:
|
||||
DPRINTF("Write data %02x\n", data);
|
||||
if (dev->data_len >= sizeof(dev->data_buf)) {
|
||||
BADF("Too many bytes sent\n");
|
||||
} else {
|
||||
dev->data_buf[dev->data_len++] = data;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BADF("Unexpected write in state %d\n", dev->mode);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Master device commands. */
|
||||
int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
|
||||
{
|
||||
if (i2c_start_transfer(bus, addr, read)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_end_transfer(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smbus_receive_byte(I2CBus *bus, uint8_t addr)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
i2c_nack(bus);
|
||||
i2c_end_transfer(bus);
|
||||
return data;
|
||||
}
|
||||
|
||||
int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
|
||||
{
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, data);
|
||||
i2c_end_transfer(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
{
|
||||
uint8_t data;
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
i2c_nack(bus);
|
||||
i2c_end_transfer(bus);
|
||||
return data;
|
||||
}
|
||||
|
||||
int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
|
||||
{
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
i2c_send(bus, data);
|
||||
i2c_end_transfer(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
{
|
||||
uint16_t data;
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
data |= i2c_recv(bus) << 8;
|
||||
i2c_nack(bus);
|
||||
i2c_end_transfer(bus);
|
||||
return data;
|
||||
}
|
||||
|
||||
int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
|
||||
{
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
i2c_send(bus, data & 0xff);
|
||||
i2c_send(bus, data >> 8);
|
||||
i2c_end_transfer(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
|
||||
int len, bool recv_len, bool send_cmd)
|
||||
{
|
||||
int rlen;
|
||||
int i;
|
||||
|
||||
if (send_cmd) {
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
}
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
if (send_cmd) {
|
||||
i2c_end_transfer(bus);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (recv_len) {
|
||||
rlen = i2c_recv(bus);
|
||||
} else {
|
||||
rlen = len;
|
||||
}
|
||||
if (rlen > len) {
|
||||
rlen = 0;
|
||||
}
|
||||
for (i = 0; i < rlen; i++) {
|
||||
data[i] = i2c_recv(bus);
|
||||
}
|
||||
i2c_nack(bus);
|
||||
i2c_end_transfer(bus);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
|
||||
int len, bool send_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len > 32)
|
||||
len = 32;
|
||||
|
||||
if (i2c_start_transfer(bus, addr, 0)) {
|
||||
return -1;
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (send_len) {
|
||||
i2c_send(bus, len);
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
i2c_send(bus, data[i]);
|
||||
}
|
||||
i2c_end_transfer(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smbus_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
sc->event = smbus_i2c_event;
|
||||
sc->recv = smbus_i2c_recv;
|
||||
sc->send = smbus_i2c_send;
|
||||
}
|
||||
|
||||
static const TypeInfo smbus_device_type_info = {
|
||||
.name = TYPE_SMBUS_DEVICE,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_size = sizeof(SMBusDevice),
|
||||
.abstract = true,
|
||||
.class_size = sizeof(SMBusDeviceClass),
|
||||
.class_init = smbus_device_class_init,
|
||||
};
|
||||
|
||||
static void smbus_device_register_types(void)
|
||||
{
|
||||
type_register_static(&smbus_device_type_info);
|
||||
}
|
||||
|
||||
type_init(smbus_device_register_types)
|
||||
+83
-55
@@ -26,39 +26,35 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/i2c/smbus.h"
|
||||
#include "hw/i2c/smbus_slave.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define TYPE_SMBUS_EEPROM "smbus-eeprom"
|
||||
|
||||
#define SMBUS_EEPROM(obj) \
|
||||
OBJECT_CHECK(SMBusEEPROMDevice, (obj), TYPE_SMBUS_EEPROM)
|
||||
|
||||
#define SMBUS_EEPROM_SIZE 256
|
||||
|
||||
typedef struct SMBusEEPROMDevice {
|
||||
SMBusDevice smbusdev;
|
||||
void *data;
|
||||
uint8_t data[SMBUS_EEPROM_SIZE];
|
||||
void *init_data;
|
||||
uint8_t offset;
|
||||
bool accessed;
|
||||
} SMBusEEPROMDevice;
|
||||
|
||||
static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
|
||||
#ifdef DEBUG
|
||||
printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
|
||||
dev->i2c.address, val);
|
||||
#endif
|
||||
eeprom->offset = val;
|
||||
}
|
||||
|
||||
static uint8_t eeprom_receive_byte(SMBusDevice *dev)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
|
||||
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
|
||||
uint8_t *data = eeprom->data;
|
||||
uint8_t val = data[eeprom->offset++];
|
||||
|
||||
eeprom->accessed = true;
|
||||
#ifdef DEBUG
|
||||
printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
|
||||
dev->i2c.address, val);
|
||||
@@ -66,48 +62,77 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
|
||||
static int eeprom_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
|
||||
int n;
|
||||
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
|
||||
uint8_t *data = eeprom->data;
|
||||
|
||||
eeprom->accessed = true;
|
||||
#ifdef DEBUG
|
||||
printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
|
||||
dev->i2c.address, cmd, buf[0]);
|
||||
dev->i2c.address, buf[0], buf[1]);
|
||||
#endif
|
||||
/* A page write operation is not a valid SMBus command.
|
||||
It is a block write without a length byte. Fortunately we
|
||||
get the full block anyway. */
|
||||
/* TODO: Should this set the current location? */
|
||||
if (cmd + len > 256)
|
||||
n = 256 - cmd;
|
||||
else
|
||||
n = len;
|
||||
memcpy(eeprom->data + cmd, buf, n);
|
||||
len -= n;
|
||||
if (len)
|
||||
memcpy(eeprom->data, buf + n, len);
|
||||
/* len is guaranteed to be > 0 */
|
||||
eeprom->offset = buf[0];
|
||||
buf++;
|
||||
len--;
|
||||
|
||||
for (; len > 0; len--) {
|
||||
data[eeprom->offset] = *buf++;
|
||||
eeprom->offset = (eeprom->offset + 1) % SMBUS_EEPROM_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
|
||||
static bool smbus_eeprom_vmstate_needed(void *opaque)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
|
||||
/* If this is the first byte then set the current position. */
|
||||
if (n == 0)
|
||||
eeprom->offset = cmd;
|
||||
/* As with writes, we implement block reads without the
|
||||
SMBus length byte. */
|
||||
return eeprom_receive_byte(dev);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
SMBusEEPROMDevice *eeprom = opaque;
|
||||
|
||||
return (eeprom->accessed || smbus_vmstate_needed(&eeprom->smbusdev)) &&
|
||||
!mc->smbus_no_migration_support;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_smbus_eeprom = {
|
||||
.name = "smbus-eeprom",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = smbus_eeprom_vmstate_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_SMBUS_DEVICE(smbusdev, SMBusEEPROMDevice),
|
||||
VMSTATE_UINT8_ARRAY(data, SMBusEEPROMDevice, SMBUS_EEPROM_SIZE),
|
||||
VMSTATE_UINT8(offset, SMBusEEPROMDevice),
|
||||
VMSTATE_BOOL(accessed, SMBusEEPROMDevice),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Reset the EEPROM contents to the initial state on a reset. This
|
||||
* isn't really how an EEPROM works, of course, but the general
|
||||
* principle of QEMU is to restore function on reset to what it would
|
||||
* be if QEMU was stopped and started.
|
||||
*
|
||||
* The proper thing to do would be to have a backing blockdev to hold
|
||||
* the contents and restore that on startup, and not do this on reset.
|
||||
* But until that time, act as if we had been stopped and restarted.
|
||||
*/
|
||||
static void smbus_eeprom_reset(DeviceState *dev)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = SMBUS_EEPROM(dev);
|
||||
|
||||
memcpy(eeprom->data, eeprom->init_data, SMBUS_EEPROM_SIZE);
|
||||
eeprom->offset = 0;
|
||||
}
|
||||
|
||||
static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
|
||||
|
||||
eeprom->offset = 0;
|
||||
smbus_eeprom_reset(dev);
|
||||
}
|
||||
|
||||
static Property smbus_eeprom_properties[] = {
|
||||
DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
|
||||
DEFINE_PROP_PTR("data", SMBusEEPROMDevice, init_data),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -117,18 +142,17 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
|
||||
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = smbus_eeprom_realize;
|
||||
sc->quick_cmd = eeprom_quick_cmd;
|
||||
sc->send_byte = eeprom_send_byte;
|
||||
dc->reset = smbus_eeprom_reset;
|
||||
sc->receive_byte = eeprom_receive_byte;
|
||||
sc->write_data = eeprom_write_data;
|
||||
sc->read_data = eeprom_read_data;
|
||||
dc->props = smbus_eeprom_properties;
|
||||
dc->vmsd = &vmstate_smbus_eeprom;
|
||||
/* Reason: pointer property "data" */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo smbus_eeprom_info = {
|
||||
.name = "smbus-eeprom",
|
||||
.name = TYPE_SMBUS_EEPROM,
|
||||
.parent = TYPE_SMBUS_DEVICE,
|
||||
.instance_size = sizeof(SMBusEEPROMDevice),
|
||||
.class_init = smbus_eeprom_class_initfn,
|
||||
@@ -145,7 +169,7 @@ void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create((BusState *) smbus, "smbus-eeprom");
|
||||
dev = qdev_create((BusState *) smbus, TYPE_SMBUS_EEPROM);
|
||||
qdev_prop_set_uint8(dev, "address", address);
|
||||
qdev_prop_set_ptr(dev, "data", eeprom_buf);
|
||||
qdev_init_nofail(dev);
|
||||
@@ -155,13 +179,17 @@ void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
|
||||
const uint8_t *eeprom_spd, int eeprom_spd_size)
|
||||
{
|
||||
int i;
|
||||
uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */
|
||||
/* XXX: make this persistent */
|
||||
|
||||
assert(nb_eeprom <= 8);
|
||||
uint8_t *eeprom_buf = g_malloc0(8 * SMBUS_EEPROM_SIZE);
|
||||
if (eeprom_spd_size > 0) {
|
||||
memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_eeprom; i++) {
|
||||
smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256));
|
||||
smbus_eeprom_init_one(smbus, 0x50 + i,
|
||||
eeprom_buf + (i * SMBUS_EEPROM_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user