I2C overhaul part 4: VIA and EEPROM edition

This commit is contained in:
RichardG867
2020-11-22 00:19:13 -03:00
parent d5867928d6
commit 3fb4727483
11 changed files with 313 additions and 129 deletions

View File

@@ -653,7 +653,7 @@ static void
acpi_i2c_set(acpi_t *dev) acpi_i2c_set(acpi_t *dev)
{ {
if (dev->i2c) { if (dev->i2c) {
/* Check direction as well due to pull-ups. */ /* Check direction as well to account for the I2C pull-ups. */
i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04));
} }
} }

View File

@@ -868,7 +868,9 @@ pipc_init(const device_t *info)
dev->nvr = device_add(&via_nvr_device); dev->nvr = device_add(&via_nvr_device);
if (dev->local >= VIA_PIPC_596A) if (dev->local >= VIA_PIPC_686B)
dev->smbus = device_add(&via_smbus_device);
else if (dev->local >= VIA_PIPC_596A)
dev->smbus = device_add(&piix4_smbus_device); dev->smbus = device_add(&piix4_smbus_device);
if (dev->local >= VIA_PIPC_596A) if (dev->local >= VIA_PIPC_596A)

View File

@@ -45,7 +45,7 @@ typedef struct {
} gl518sm_t; } gl518sm_t;
static void gl518sm_i2c_start(void *bus, uint8_t addr, void *priv); static uint8_t gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv);
static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv);
static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg); static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg);
static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
@@ -87,12 +87,14 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr)
} }
static void static uint8_t
gl518sm_i2c_start(void *bus, uint8_t addr, void *priv) gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv)
{ {
gl518sm_t *dev = (gl518sm_t *) priv; gl518sm_t *dev = (gl518sm_t *) priv;
dev->i2c_state = 0; dev->i2c_state = 0;
return 1;
} }
@@ -173,11 +175,11 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
break; break;
case 1: case 1:
gl518sm_write(dev, dev->addr_register, data); gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) & 0xff00) | data);
break; break;
case 2: case 2:
gl518sm_write(dev, dev->addr_register, (data << 8) | gl518sm_read(dev, dev->addr_register)); gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) << 8) | data);
break; break;
default: default:

View File

@@ -30,7 +30,7 @@
#define LM75_TEMP_TO_REG(t) ((t) << 8) #define LM75_TEMP_TO_REG(t) ((t) << 8)
static void lm75_i2c_start(void *bus, uint8_t addr, void *priv); static uint8_t lm75_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv);
static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static void lm75_reset(lm75_t *dev); static void lm75_reset(lm75_t *dev);
@@ -59,7 +59,7 @@ lm75_log(const char *fmt, ...)
void void
lm75_remap(lm75_t *dev, uint8_t addr) lm75_remap(lm75_t *dev, uint8_t addr)
{ {
lm75_log("LM75: remapping to I2C %02Xh\n", addr); lm75_log("LM75: remapping to SMBus %02Xh\n", addr);
if (dev->i2c_addr < 0x80) if (dev->i2c_addr < 0x80)
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev);
@@ -71,12 +71,14 @@ lm75_remap(lm75_t *dev, uint8_t addr)
} }
static void static uint8_t
lm75_i2c_start(void *bus, uint8_t addr, void *priv) lm75_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv)
{ {
lm75_t *dev = (lm75_t *) priv; lm75_t *dev = (lm75_t *) priv;
dev->i2c_state = 0; dev->i2c_state = 0;
return 1;
} }
@@ -93,7 +95,7 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv)
to access some of its proprietary registers. Pass this operation on to to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */ the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr); i2c_start(i2c_smbus, dev->as99127f_i2c_addr, 1);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr); ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
@@ -149,7 +151,10 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) { if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) {
return 0; return 0;
} else if (dev->i2c_state == 0) { } else if (dev->i2c_state == 0) {
dev->addr_register = data; dev->i2c_state = 1;
/* Linux lm75.c driver relies on a 3-bit address register that doesn't change if bit 2 is set. */
if ((dev->as99127f_i2c_addr >= 0x80) && !(data & 0x04))
dev->addr_register = (data & 0x7);
return 1; return 1;
} }
@@ -157,7 +162,7 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
to access some of its proprietary registers. Pass this operation on to to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */ the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr); i2c_start(i2c_smbus, dev->as99127f_i2c_addr, 0);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
@@ -175,13 +180,14 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
case 0x2: /* Thyst */ case 0x2: /* Thyst */
lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data); lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data);
break; break;
case 0x3: /* Tos */ case 0x3: /* Tos */
lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data); lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data);
break; break;
} }
} }
if (++dev->i2c_state > 2) if (dev->i2c_state == 1)
dev->i2c_state = 2; dev->i2c_state = 2;
return 1; return 1;

View File

@@ -60,7 +60,7 @@ typedef struct {
} lm78_t; } lm78_t;
static void lm78_i2c_start(void *bus, uint8_t addr, void *priv); static uint8_t lm78_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv);
static uint8_t lm78_isa_read(uint16_t port, void *priv); static uint8_t lm78_isa_read(uint16_t port, void *priv);
static uint8_t lm78_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm78_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank); static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank);
@@ -69,7 +69,7 @@ static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
static void lm78_reset(lm78_t *dev, uint8_t initialization); static void lm78_reset(lm78_t *dev, uint8_t initialization);
#define ENABLE_LM78_LOG 1
#ifdef ENABLE_LM78_LOG #ifdef ENABLE_LM78_LOG
int lm78_do_log = ENABLE_LM78_LOG; int lm78_do_log = ENABLE_LM78_LOG;
@@ -118,12 +118,14 @@ lm78_remap(lm78_t *dev, uint8_t addr)
} }
static void static uint8_t
lm78_i2c_start(void *bus, uint8_t addr, void *priv) lm78_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv)
{ {
lm78_t *dev = (lm78_t *) priv; lm78_t *dev = (lm78_t *) priv;
dev->i2c_state = 0; dev->i2c_state = 0;
return 1;
} }

View File

@@ -30,7 +30,7 @@
typedef struct _i2c_ { typedef struct _i2c_ {
void (*start)(void *bus, uint8_t addr, void *priv); uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv);
uint8_t (*read)(void *bus, uint8_t addr, void *priv); uint8_t (*read)(void *bus, uint8_t addr, void *priv);
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv); uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv);
void (*stop)(void *bus, uint8_t addr, void *priv); void (*stop)(void *bus, uint8_t addr, void *priv);
@@ -84,16 +84,43 @@ i2c_addbus(char *name)
void void
i2c_removebus(void *bus_handle) i2c_removebus(void *bus_handle)
{ {
int c;
i2c_t *p, *q;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
if (!bus_handle) if (!bus_handle)
return; return;
free(bus_handle); for (c = 0; c < NADDRS; c++) {
p = bus->devices[c];
if (!p)
continue;
while(p) {
q = p->next;
free(p);
p = q;
}
}
free(bus);
}
char *
i2c_getbusname(void *bus_handle)
{
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
if (!bus_handle)
return;
return(bus->name);
} }
void void
i2c_sethandler(void *bus_handle, uint8_t base, int size, i2c_sethandler(void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
@@ -103,7 +130,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size,
i2c_t *p, *q = NULL; i2c_t *p, *q = NULL;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
if (!bus_handle || ((base + size) >= NADDRS)) if (!bus_handle || ((base + size) > NADDRS))
return; return;
for (c = 0; c < size; c++) { for (c = 0; c < size; c++) {
@@ -133,7 +160,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size,
void void
i2c_removehandler(void *bus_handle, uint8_t base, int size, i2c_removehandler(void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
@@ -143,7 +170,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
i2c_t *p, *q; i2c_t *p, *q;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
if (!bus_handle || ((base + size) >= NADDRS)) if (!bus_handle || ((base + size) > NADDRS))
return; return;
for (c = 0; c < size; c++) { for (c = 0; c < size; c++) {
@@ -152,7 +179,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
continue; continue;
while(p) { while(p) {
q = p->next; q = p->next;
if ((p->read == read) && (p->write == write) && (p->priv == priv)) { if ((p->start == start) && (p->read == read) && (p->write == write) && (p->stop == stop) && (p->priv == priv)) {
if (p->prev) if (p->prev)
p->prev->next = p->next; p->prev->next = p->next;
else else
@@ -173,7 +200,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
void void
i2c_handler(int set, void *bus_handle, uint8_t base, int size, i2c_handler(int set, void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
@@ -200,26 +227,29 @@ i2c_has_device(void *bus_handle, uint8_t addr)
} }
void uint8_t
i2c_start(void *bus_handle, uint8_t addr) i2c_start(void *bus_handle, uint8_t addr, uint8_t read)
{ {
uint8_t ret = 0;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p; i2c_t *p;
if (!bus) if (!bus)
return; return(ret);
p = bus->devices[addr]; p = bus->devices[addr];
if (p) { if (p) {
while(p) { while(p) {
if (p->start) { if (p->start) {
p->start(bus_handle, addr, p->priv); ret |= p->start(bus_handle, addr, read, p->priv);
} }
p = p->next; p = p->next;
} }
} }
i2c_log("I2C: start(%s, %02X)\n", bus->name, addr); i2c_log("I2C: start(%s, %02X)\n", bus->name, addr);
return(ret);
} }
@@ -264,7 +294,7 @@ i2c_write(void *bus_handle, uint8_t addr, uint8_t data)
if (p) { if (p) {
while(p) { while(p) {
if (p->write) { if (p->write) {
ret = p->write(bus_handle, addr, data, p->priv); ret |= p->write(bus_handle, addr, data, p->priv);
} }
p = p->next; p = p->next;
} }

View File

@@ -29,11 +29,11 @@ typedef struct {
void *i2c; void *i2c;
uint8_t addr, *data, writable; uint8_t addr, *data, writable;
uint16_t addr_mask, addr_register; uint32_t addr_mask, addr_register;
uint8_t i2c_state; uint8_t addr_len, addr_pos;
} i2c_eeprom_t; } i2c_eeprom_t;
#define ENABLE_I2C_EEPROM_LOG 1
#ifdef ENABLE_I2C_EEPROM_LOG #ifdef ENABLE_I2C_EEPROM_LOG
int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG; int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG;
@@ -54,15 +54,17 @@ i2c_eeprom_log(const char *fmt, ...)
#endif #endif
void uint8_t
i2c_eeprom_start(void *bus, uint8_t addr, void *priv) i2c_eeprom_start(void *bus, uint8_t addr, uint8_t read, void *priv)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
i2c_eeprom_log("I2C EEPROM: start()\n"); i2c_eeprom_log("I2C EEPROM %s %02X: start()\n", i2c_getbusname(dev->i2c), dev->addr);
dev->i2c_state = 0; dev->addr_pos = 0;
dev->addr_register = (addr << 8) & dev->addr_mask; dev->addr_register = (addr << dev->addr_len) & dev->addr_mask;
return 1;
} }
@@ -72,7 +74,7 @@ i2c_eeprom_read(void *bus, uint8_t addr, void *priv)
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
uint8_t ret = dev->data[dev->addr_register]; uint8_t ret = dev->data[dev->addr_register];
i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret); i2c_eeprom_log("I2C EEPROM %s %02X: read(%06X) = %02X\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, ret);
if (++dev->addr_register > dev->addr_mask) /* roll-over */ if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0; dev->addr_register = 0;
@@ -85,13 +87,17 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
if (dev->i2c_state == 0) { if (dev->addr_pos < dev->addr_len) {
dev->i2c_state = 1; dev->addr_register <<= 8;
dev->addr_register = ((addr << 8) | data) & dev->addr_mask; dev->addr_register |= data;
i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register); dev->addr_register &= (1 << dev->addr_len) - 1;
dev->addr_register |= addr << dev->addr_len;
dev->addr_register &= dev->addr_mask;
i2c_eeprom_log("I2C EEPROM %s %02X: write(address, %04X)\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register);
dev->addr_pos += 8;
} else { } else {
i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked"); i2c_eeprom_log("I2C EEPROM %s %02X: write(%06X, %02X) = %d\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, data, !!dev->writable);
if (dev->writable) if (dev->writable)
dev->data[dev->addr_register] = data; dev->data[dev->addr_register] = data;
if (++dev->addr_register > dev->addr_mask) /* roll-over */ if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0; dev->addr_register = 0;
@@ -103,21 +109,24 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
void * void *
i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable) i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t));
memset(dev, 0, sizeof(i2c_eeprom_t)); memset(dev, 0, sizeof(i2c_eeprom_t));
i2c_eeprom_log("I2C EEPROM: init(%02X, %d, %d)\n", addr, size, writable); size &= 0x7fffff; /* address space limit of 8 MB = 7 bits from I2C address + 16 bits */
i2c_eeprom_log("I2C EEPROM %s %02X: init(%d, %d)\n", i2c_getbusname(i2c), addr, size, writable);
dev->i2c = i2c; dev->i2c = i2c;
dev->addr = addr; dev->addr = addr;
dev->data = data; dev->data = data;
dev->writable = writable; dev->writable = writable;
dev->addr_len = (size >= 4096) ? 16 : 8; /* use 16-bit addresses on 24C32 and above */
dev->addr_mask = size - 1; dev->addr_mask = size - 1;
i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
return dev; return dev;
} }
@@ -128,9 +137,9 @@ i2c_eeprom_close(void *dev_handle)
{ {
i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle;
i2c_eeprom_log("I2C EEPROM: close()\n"); i2c_eeprom_log("I2C EEPROM %s %02X: close()\n", i2c_getbusname(dev->i2c), dev->addr);
i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
free(dev); free(dev);
} }

View File

@@ -39,6 +39,7 @@ enum {
I2C_TRANSMIT_START, I2C_TRANSMIT_START,
I2C_TRANSMIT, I2C_TRANSMIT,
I2C_ACKNOWLEDGE, I2C_ACKNOWLEDGE,
I2C_NEGACKNOWLEDGE,
I2C_TRANSACKNOWLEDGE, I2C_TRANSACKNOWLEDGE,
I2C_TRANSMIT_WAIT I2C_TRANSMIT_WAIT
}; };
@@ -55,7 +56,7 @@ typedef struct {
char *bus_name; char *bus_name;
void *i2c; void *i2c;
uint8_t scl, sda, state, slave_state, slave_addr, uint8_t scl, sda, state, slave_state, slave_addr,
slave_rw, last_sda, pos, transmit, byte; slave_read, last_sda, pos, transmit, byte;
} i2c_gpio_t; } i2c_gpio_t;
@@ -113,11 +114,11 @@ void
i2c_gpio_next_byte(i2c_gpio_t *dev) i2c_gpio_next_byte(i2c_gpio_t *dev)
{ {
dev->byte = i2c_read(dev->i2c, dev->slave_addr); dev->byte = i2c_read(dev->i2c, dev->slave_addr);
i2c_gpio_log(1, "I2C GPIO %s: next_byte() = %02X\n", dev->bus_name, dev->byte); i2c_gpio_log(1, "I2C GPIO %s: Transmitting data %02X\n", dev->bus_name, dev->byte);
} }
void uint8_t
i2c_gpio_write(i2c_gpio_t *dev) i2c_gpio_write(i2c_gpio_t *dev)
{ {
uint8_t i; uint8_t i;
@@ -126,19 +127,20 @@ i2c_gpio_write(i2c_gpio_t *dev)
case SLAVE_IDLE: case SLAVE_IDLE:
i = dev->slave_addr; i = dev->slave_addr;
dev->slave_addr = dev->byte >> 1; dev->slave_addr = dev->byte >> 1;
dev->slave_rw = dev->byte & 1; dev->slave_read = dev->byte & 1;
i2c_gpio_log(1, "I2C GPIO %s: Initiating transfer to address %02X rw %d\n", dev->bus_name, dev->slave_addr, dev->slave_rw); i2c_gpio_log(1, "I2C GPIO %s: Initiating %s address %02X\n", dev->bus_name, dev->slave_read ? "read from" : "write to", dev->slave_addr);
if (!i2c_has_device(dev->i2c, dev->slave_addr)) { if (!i2c_has_device(dev->i2c, dev->slave_addr)) {
dev->slave_state = SLAVE_INVALID; dev->slave_state = SLAVE_INVALID;
break; dev->slave_addr = 0xff;
return I2C_NEGACKNOWLEDGE;
} }
if (i == 0xff) if (i == 0xff) /* start only once per transfer */
i2c_start(dev->i2c, dev->slave_addr); i2c_start(dev->i2c, dev->slave_addr, dev->slave_read);
if (dev->slave_rw) { if (dev->slave_read) {
dev->slave_state = SLAVE_SENDDATA; dev->slave_state = SLAVE_SENDDATA;
dev->transmit = TRANSMITTER_SLAVE; dev->transmit = TRANSMITTER_SLAVE;
dev->byte = i2c_read(dev->i2c, dev->slave_addr); dev->byte = i2c_read(dev->i2c, dev->slave_addr);
@@ -150,15 +152,22 @@ i2c_gpio_write(i2c_gpio_t *dev)
case SLAVE_RECEIVEADDR: case SLAVE_RECEIVEADDR:
i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte); i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte); dev->slave_state = dev->slave_read ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte))
return I2C_NEGACKNOWLEDGE;
break; break;
case SLAVE_RECEIVEDATA: case SLAVE_RECEIVEDATA:
i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte); i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte); if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte))
return I2C_NEGACKNOWLEDGE;
break; break;
case SLAVE_INVALID:
return I2C_NEGACKNOWLEDGE;
} }
return I2C_ACKNOWLEDGE;
} }
@@ -167,7 +176,7 @@ i2c_gpio_stop(i2c_gpio_t *dev)
{ {
i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name); i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name);
if (dev->slave_addr != 0xff) if (dev->slave_addr != 0xff) /* don't stop if no transfer was in progress */
i2c_stop(dev->i2c, dev->slave_addr); i2c_stop(dev->i2c, dev->slave_addr);
dev->slave_addr = 0xff; dev->slave_addr = 0xff;
@@ -183,8 +192,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
switch (dev->state) { switch (dev->state) {
case I2C_IDLE: case I2C_IDLE:
/* !dev->scl check breaks NCR SDMS. */ /* dev->scl check breaks NCR SDMS. */
if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */ if (scl && dev->last_sda && !sda) { /* start bit */
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name); i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name);
dev->state = I2C_RECEIVE; dev->state = I2C_RECEIVE;
dev->pos = 0; dev->pos = 0;
@@ -203,10 +212,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
dev->byte |= 1; dev->byte |= 1;
else else
dev->byte &= 0xfe; dev->byte &= 0xfe;
if (++dev->pos == 8) { if (++dev->pos == 8)
i2c_gpio_write(dev); dev->state = i2c_gpio_write(dev);
dev->state = I2C_ACKNOWLEDGE;
}
} else if (dev->scl && scl) { } else if (dev->scl && scl) {
if (sda && !dev->last_sda) { /* stop bit */ if (sda && !dev->last_sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name); i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name);
@@ -222,13 +229,23 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_ACKNOWLEDGE: case I2C_ACKNOWLEDGE:
if (!dev->scl && scl) { if (!dev->scl && scl) {
i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer\n", dev->bus_name); i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer to %02X\n", dev->bus_name, dev->slave_addr);
sda = 0; sda = 0;
dev->pos = 0; dev->pos = 0;
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
} }
break; break;
case I2C_NEGACKNOWLEDGE:
if (!dev->scl && scl) {
i2c_gpio_log(2, "I2C GPIO %s: Nacking transfer\n", dev->bus_name);
sda = 1;
dev->pos = 0;
dev->state = I2C_IDLE;
dev->slave_state = SLAVE_IDLE;
}
break;
case I2C_TRANSACKNOWLEDGE: case I2C_TRANSACKNOWLEDGE:
if (!dev->scl && scl) { if (!dev->scl && scl) {
if (sda) { /* not acknowledged; must be end of transfer */ if (sda) { /* not acknowledged; must be end of transfer */
@@ -306,12 +323,17 @@ uint8_t
i2c_gpio_get_sda(void *dev_handle) i2c_gpio_get_sda(void *dev_handle)
{ {
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
if ((dev->state == I2C_TRANSMIT) || (dev->state == I2C_ACKNOWLEDGE)) switch (dev->state) {
return dev->sda; case I2C_TRANSMIT:
else if (dev->state == I2C_RECEIVE_WAIT) case I2C_ACKNOWLEDGE:
return 0; /* ack */ return dev->sda;
else
return 1; case I2C_RECEIVE_WAIT:
return 0; /* ack */
default:
return 1;
}
} }

View File

@@ -98,95 +98,189 @@ static void
smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
{ {
smbus_piix4_t *dev = (smbus_piix4_t *) priv; smbus_piix4_t *dev = (smbus_piix4_t *) priv;
uint8_t smbus_addr, smbus_read, prev_stat; uint8_t smbus_addr, cmd, read, block_len, prev_stat, timer_bytes = 0;
smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val);
prev_stat = dev->next_stat; prev_stat = dev->next_stat;
dev->next_stat = 0; dev->next_stat = 0x00;
switch (addr - dev->io_base) { switch (addr - dev->io_base) {
case 0x00: case 0x00:
/* some status bits are reset by writing 1 to them */ for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */
for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) {
if (val & smbus_addr) if (val & smbus_addr)
dev->stat &= ~smbus_addr; dev->stat &= ~smbus_addr;
} }
break; break;
case 0x02: case 0x02:
dev->ctl = val & ~(0x40); /* START always reads 0 */ dev->ctl = val & ((dev->local == SMBUS_VIA) ? 0x3f : 0x1f);
if (val & 0x02) { /* cancel an in-progress command if KILL is set */ if (val & 0x02) { /* cancel an in-progress command if KILL is set */
/* cancel only if a command is in progress */ if (prev_stat) { /* cancel only if a command is in progress */
if (prev_stat) {
dev->stat = 0x10; /* raise FAILED */
timer_disable(&dev->response_timer); timer_disable(&dev->response_timer);
dev->stat = 0x10; /* raise FAILED */
} }
} }
if (val & 0x40) { /* dispatch command if START is set */ if (val & 0x40) { /* dispatch command if START is set */
timer_bytes++; /* address */
smbus_addr = (dev->addr >> 1); smbus_addr = (dev->addr >> 1);
if (!i2c_has_device(i2c_smbus, smbus_addr)) { read = dev->addr & 0x01;
/* raise DEV_ERR if no device is at this address */
dev->next_stat = 0x4; /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */
if (!i2c_has_device(i2c_smbus, smbus_addr) || !i2c_start(i2c_smbus, smbus_addr, read)) {
dev->next_stat = 0x04;
break; break;
} }
smbus_read = dev->addr & 0x01;
/* start transaction */ dev->next_stat = 0x02; /* raise INTER (command completed) by default */
i2c_start(i2c_smbus, smbus_addr);
/* decode the 3-bit command protocol */ /* Decode the command protocol.
dev->next_stat = 0x2; /* raise INTER (command completed) by default */ VIA-specific modes (0x4 and [0x6:0xf]) are undocumented and required real hardware research. */
switch ((val >> 2) & 0x7) { cmd = (val >> 2) & 0xf;
smbus_piix4_log("SMBus PIIX4: protocol=%X cmd=%02X data0=%02X data1=%02X\n", cmd, dev->cmd, dev->data0, dev->data1);
switch (cmd) {
case 0x0: /* quick R/W */ case 0x0: /* quick R/W */
break; break;
case 0x1: /* byte R/W */ case 0x1: /* byte R/W */
if (smbus_read) if (read) /* byte read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr); dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else else /* byte write */
i2c_write(i2c_smbus, smbus_addr, dev->data0); i2c_write(i2c_smbus, smbus_addr, dev->data0);
timer_bytes++;
break; break;
case 0x2: /* byte data R/W */ case 0x2: /* byte data R/W */
/* command write */
i2c_write(i2c_smbus, smbus_addr, dev->cmd); i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if (smbus_read) timer_bytes++;
if (read) /* byte read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr); dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else else /* byte write */
i2c_write(i2c_smbus, smbus_addr, dev->data0); i2c_write(i2c_smbus, smbus_addr, dev->data0);
timer_bytes++;
break; break;
case 0x3: /* word data R/W */ case 0x3: /* word data R/W */
/* command write */
i2c_write(i2c_smbus, smbus_addr, dev->cmd); i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if (smbus_read) { timer_bytes++;
if (read) { /* word read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr); dev->data0 = i2c_read(i2c_smbus, smbus_addr);
dev->data1 = i2c_read(i2c_smbus, smbus_addr); dev->data1 = i2c_read(i2c_smbus, smbus_addr);
} else { } else { /* word write */
i2c_write(i2c_smbus, smbus_addr, dev->data0); i2c_write(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data1); i2c_write(i2c_smbus, smbus_addr, dev->data1);
} }
timer_bytes += 2;
break;
case 0x4: /* process call */
if (dev->local != SMBUS_VIA) /* VIA only */
goto unknown_protocol;
if (!read) { /* command write (only when writing) */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
timer_bytes++;
}
/* fall-through */
case 0xc: /* I2C process call */
if (!read) { /* word write (only when writing) */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data1);
timer_bytes += 2;
}
/* word read */
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
dev->data1 = i2c_read(i2c_smbus, smbus_addr);
timer_bytes += 2;
break; break;
case 0x5: /* block R/W */ case 0x5: /* block R/W */
timer_bytes++; /* account for the SMBus length byte now */
/* fall-through */
case 0xd: /* I2C block R/W */
i2c_write(i2c_smbus, smbus_addr, dev->cmd); i2c_write(i2c_smbus, smbus_addr, dev->cmd);
/* SMBus block data is preceded by a length */ timer_bytes++;
if (smbus_read) {
dev->data0 = i2c_read(i2c_smbus, smbus_addr); if (read) {
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) /* block read [data0] (I2C) or [first byte] (SMBus) bytes */
dev->data[smbus_read] = i2c_read(i2c_smbus, smbus_addr); block_len = (cmd == 0x5) ? i2c_read(i2c_smbus, smbus_addr) : dev->data0;
for (read = 0; read < block_len; read++)
dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr);
} else { } else {
i2c_write(i2c_smbus, smbus_addr, dev->data0); block_len = dev->data0;
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) if (cmd == 0x5) /* send length [data0] as first byte on SMBus */
i2c_write(i2c_smbus, smbus_addr, dev->data[smbus_read]); i2c_write(i2c_smbus, smbus_addr, block_len);
/* block write [data0] bytes */
for (read = 0; read < block_len; read++) {
if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK]))
break;
}
} }
timer_bytes += read;
break; break;
default: case 0x6: /* I2C with 10-bit address */
/* other command protocols have undefined behavior, but raise DEV_ERR to be safe */ if (dev->local != SMBUS_VIA) /* VIA only */
dev->next_stat = 0x4; goto unknown_protocol;
/* command write */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
timer_bytes += 1;
/* fall-through */
case 0xe: /* I2C with 7-bit address */
if (!read) { /* word write (only when writing) */
i2c_write(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data1);
timer_bytes += 2;
}
/* block read [first byte] bytes */
block_len = dev->data[0];
for (read = 0; read < block_len; read++)
dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr);
timer_bytes += read;
break;
case 0xf: /* universal */
/* block write [data0] bytes */
for (read = 0; read < dev->data0; read++) {
if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK]))
break;
}
timer_bytes += read;
/* block read [data1] bytes */
for (read = 0; read < dev->data1; read++)
dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr);
timer_bytes += read;
break;
default: /* unknown */
unknown_protocol:
dev->next_stat = 0x04; /* raise DEV_ERR */
timer_bytes = 0;
break; break;
} }
/* stop transaction */ /* Finish transfer. */
i2c_stop(i2c_smbus, smbus_addr); i2c_stop(i2c_smbus, smbus_addr);
} }
break; break;
@@ -214,11 +308,11 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
break; break;
} }
/* if a status register update was given, dispatch it after 10us to ensure nothing breaks */ if (dev->next_stat) { /* schedule dispatch of any pending status register update */
if (dev->next_stat) { dev->stat = 0x01; /* raise HOST_BUSY while waiting */
dev->stat = 0x1; /* raise HOST_BUSY while waiting */
timer_disable(&dev->response_timer); timer_disable(&dev->response_timer);
timer_set_delay_u64(&dev->response_timer, 10 * TIMER_USEC); /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */
timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC);
} }
} }
@@ -228,7 +322,7 @@ smbus_piix4_response(void *priv)
{ {
smbus_piix4_t *dev = (smbus_piix4_t *) priv; smbus_piix4_t *dev = (smbus_piix4_t *) priv;
/* dispatch the status register update */ /* Dispatch the status register update. */
dev->stat = dev->next_stat; dev->stat = dev->next_stat;
} }
@@ -253,7 +347,8 @@ smbus_piix4_init(const device_t *info)
smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t));
memset(dev, 0, sizeof(smbus_piix4_t)); memset(dev, 0, sizeof(smbus_piix4_t));
i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4"); dev->local = info->local;
i2c_smbus = dev->i2c = i2c_addbus((dev->local == SMBUS_VIA) ? "smbus_vt82c686b" : "smbus_piix4");
timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); timer_add(&dev->response_timer, smbus_piix4_response, dev, 0);
@@ -277,7 +372,16 @@ smbus_piix4_close(void *priv)
const device_t piix4_smbus_device = { const device_t piix4_smbus_device = {
"PIIX4-compatible SMBus Host Controller", "PIIX4-compatible SMBus Host Controller",
DEVICE_AT, DEVICE_AT,
0, SMBUS_PIIX4,
smbus_piix4_init, smbus_piix4_close, NULL,
{ NULL }, NULL, NULL,
NULL
};
const device_t via_smbus_device = {
"VIA VT82C686B SMBus Host Controller",
DEVICE_AT,
SMBUS_VIA,
smbus_piix4_init, smbus_piix4_close, NULL, smbus_piix4_init, smbus_piix4_close, NULL,
{ NULL }, NULL, NULL, { NULL }, NULL, NULL,
NULL NULL

View File

@@ -25,36 +25,37 @@ extern void *i2c_smbus;
/* i2c.c */ /* i2c.c */
extern void *i2c_addbus(char *name); extern void *i2c_addbus(char *name);
extern void i2c_removebus(void *bus_handle); extern void i2c_removebus(void *bus_handle);
extern char *i2c_getbusname(void *bus_handle);
extern void i2c_sethandler(void *bus_handle, uint8_t base, int size, extern void i2c_sethandler(void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv); void *priv);
extern void i2c_removehandler(void *bus_handle, uint8_t base, int size, extern void i2c_removehandler(void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv); void *priv);
extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size, extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size,
void (*start)(void *bus, uint8_t addr, void *priv), uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv); void *priv);
extern uint8_t i2c_has_device(void *bus_handle, uint8_t addr); extern uint8_t i2c_has_device(void *bus_handle, uint8_t addr);
extern void i2c_start(void *bus_handle, uint8_t addr); extern uint8_t i2c_start(void *bus_handle, uint8_t addr, uint8_t read);
extern uint8_t i2c_read(void *bus_handle, uint8_t addr); extern uint8_t i2c_read(void *bus_handle, uint8_t addr);
extern uint8_t i2c_write(void *bus_handle, uint8_t addr, uint8_t data); extern uint8_t i2c_write(void *bus_handle, uint8_t addr, uint8_t data);
extern void i2c_stop(void *bus_handle, uint8_t addr); extern void i2c_stop(void *bus_handle, uint8_t addr);
/* i2c_eeprom.c */ /* i2c_eeprom.c */
extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable); extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable);
extern void i2c_eeprom_close(void *dev_handle); extern void i2c_eeprom_close(void *dev_handle);
/* i2c_gpio.c */ /* i2c_gpio.c */

View File

@@ -19,15 +19,20 @@
#define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 #define SMBUS_PIIX4_BLOCK_DATA_SIZE 32
#define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1)
typedef struct enum {
{ SMBUS_PIIX4 = 0,
SMBUS_VIA
};
typedef struct {
uint32_t local;
uint16_t io_base; uint16_t io_base;
uint8_t stat, next_stat, ctl, cmd, addr, uint8_t stat, next_stat, ctl, cmd, addr,
data0, data1, data0, data1,
index, index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE];
data[SMBUS_PIIX4_BLOCK_DATA_SIZE];
pc_timer_t response_timer; pc_timer_t response_timer;
void *i2c; void *i2c;
} smbus_piix4_t; } smbus_piix4_t;
@@ -38,6 +43,7 @@ extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t
#ifdef EMU_DEVICE_H #ifdef EMU_DEVICE_H
extern const device_t piix4_smbus_device; extern const device_t piix4_smbus_device;
extern const device_t via_smbus_device;
#endif #endif