The attached patch implements an I2C/SMBus framework for qemu.
It provides an API for connecting emulated I2C devices, and implements SMBus
as a layer on top of that.
Currently the only i2c device in CVS is the piix eeprom. I've tested this as
much as I can - linux successfully reads the eeprom contents.
I've also used the same framework for several different boards.
I will apply in a day or so if there are no serious objections.
Paul
Index: Makefile.target
===
RCS file: /sources/qemu/qemu/Makefile.target,v
retrieving revision 1.169
diff -u -p -r1.169 Makefile.target
--- Makefile.target 8 May 2007 21:05:55 - 1.169
+++ Makefile.target 12 May 2007 17:50:21 -
@@ -401,6 +401,8 @@ SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
+VL_OBJS += i2c.o smbus.o
+
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
Index: vl.h
===
RCS file: /sources/qemu/qemu/vl.h,v
retrieving revision 1.234
diff -u -p -r1.234 vl.h
--- vl.h 9 May 2007 20:25:36 - 1.234
+++ vl.h 12 May 2007 17:50:21 -
@@ -1125,17 +1125,16 @@ int pit_get_out(PITState *pit, int chann
void pcspk_init(PITState *);
int pcspk_audio_init(AudioState *, qemu_irq *pic);
+#include hw/i2c.h
+
#include hw/smbus.h
/* acpi.c */
extern int acpi_enabled;
-void piix4_pm_init(PCIBus *bus, int devfn);
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void acpi_bios_init(void);
-/* smbus_eeprom.c */
-SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf);
-
/* pc.c */
extern QEMUMachine pc_machine;
extern QEMUMachine isapc_machine;
Index: hw/acpi.c
===
RCS file: /sources/qemu/qemu/hw/acpi.c,v
retrieving revision 1.10
diff -u -p -r1.10 acpi.c
--- hw/acpi.c 15 Apr 2007 23:54:20 - 1.10
+++ hw/acpi.c 12 May 2007 17:50:21 -
@@ -35,7 +35,7 @@ typedef struct PIIX4PMState {
uint8_t apms;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
-SMBusDevice *smb_dev[128];
+i2c_bus *smbus;
uint8_t smb_stat;
uint8_t smb_ctl;
uint8_t smb_cmd;
@@ -63,9 +63,6 @@ typedef struct PIIX4PMState {
#define SMBHSTDAT1 0x06
#define SMBBLKDAT 0x07
-/* Note: only used for piix4_smbus_register_device */
-static PIIX4PMState *piix4_pm_state;
-
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
@@ -258,59 +255,44 @@ static void smb_transaction(PIIX4PMState
uint8_t read = s-smb_addr 0x01;
uint8_t cmd = s-smb_cmd;
uint8_t addr = s-smb_addr 1;
-SMBusDevice *dev = s-smb_dev[addr];
+i2c_bus *bus = s-smbus;
#ifdef DEBUG
printf(SMBus trans addr=0x%02x prot=0x%02x\n, addr, prot);
#endif
-if (!dev) goto error;
-
switch(prot) {
case 0x0:
-if (!dev-quick_cmd) goto error;
-(*dev-quick_cmd)(dev, read);
+smbus_quick_command(bus, addr, read);
break;
case 0x1:
if (read) {
-if (!dev-receive_byte) goto error;
-s-smb_data0 = (*dev-receive_byte)(dev);
-}
-else {
-if (!dev-send_byte) goto error;
-(*dev-send_byte)(dev, cmd);
+s-smb_data0 = smbus_receive_byte(bus, addr);
+} else {
+smbus_send_byte(bus, addr, cmd);
}
break;
case 0x2:
if (read) {
-if (!dev-read_byte) goto error;
-s-smb_data0 = (*dev-read_byte)(dev, cmd);
-}
-else {
-if (!dev-write_byte) goto error;
-(*dev-write_byte)(dev, cmd, s-smb_data0);
+s-smb_data0 = smbus_read_byte(bus, addr, cmd);
+} else {
+smbus_write_byte(bus, addr, cmd, s-smb_data0);
}
break;
case 0x3:
if (read) {
uint16_t val;
-if (!dev-read_word) goto error;
-val = (*dev-read_word)(dev, cmd);
+smbus_read_word(bus, addr, cmd);
s-smb_data0 = val;
s-smb_data1 = val 8;
-}
-else {
-if (!dev-write_word) goto error;
-(*dev-write_word)(dev, cmd, (s-smb_data1 8) | s-smb_data0);
+} else {
+smbus_write_word(bus, addr, cmd, (s-smb_data1 8) | s-smb_data0);
}
break;
case 0x5:
if (read) {
-if (!dev-read_block) goto error;
-s-smb_data0 = (*dev-read_block)(dev, cmd, s-smb_data);
-}
-else {
-if (!dev-write_block) goto error;
-(*dev-write_block)(dev, cmd, s-smb_data0, s-smb_data);
+s-smb_data0 = smbus_read_block(bus, addr, cmd, s-smb_data);
+} else {
+smbus_write_block(bus, addr, cmd, s-smb_data, s-smb_data0);
}
break;
default:
@@ -469,7 +451,7 @@ static int pm_load(QEMUFile* f,void* opa
return 0;
}