I2C overhaul part 4: VIA and EEPROM edition
This commit is contained in:
@@ -653,7 +653,7 @@ static void
|
||||
acpi_i2c_set(acpi_t *dev)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@@ -868,7 +868,9 @@ pipc_init(const device_t *info)
|
||||
|
||||
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);
|
||||
|
||||
if (dev->local >= VIA_PIPC_596A)
|
||||
|
@@ -45,7 +45,7 @@ typedef struct {
|
||||
} 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 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);
|
||||
@@ -87,12 +87,14 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr)
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
|
||||
dev->i2c_state = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,11 +175,11 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gl518sm_write(dev, dev->addr_register, data);
|
||||
gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) & 0xff00) | data);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
|
@@ -30,7 +30,7 @@
|
||||
#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_write(void *bus, uint8_t addr, uint8_t data, void *priv);
|
||||
static void lm75_reset(lm75_t *dev);
|
||||
@@ -59,7 +59,7 @@ lm75_log(const char *fmt, ...)
|
||||
void
|
||||
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)
|
||||
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
|
||||
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)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
|
||||
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
|
||||
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)) {
|
||||
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);
|
||||
ret = i2c_read(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))) {
|
||||
return 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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)) {
|
||||
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, data);
|
||||
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 */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data);
|
||||
break;
|
||||
|
||||
case 0x3: /* Tos */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (++dev->i2c_state > 2)
|
||||
if (dev->i2c_state == 1)
|
||||
dev->i2c_state = 2;
|
||||
|
||||
return 1;
|
||||
|
@@ -60,7 +60,7 @@ typedef struct {
|
||||
} 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_i2c_read(void *bus, uint8_t addr, void *priv);
|
||||
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 void lm78_reset(lm78_t *dev, uint8_t initialization);
|
||||
|
||||
#define ENABLE_LM78_LOG 1
|
||||
|
||||
#ifdef ENABLE_LM78_LOG
|
||||
int lm78_do_log = ENABLE_LM78_LOG;
|
||||
|
||||
@@ -118,12 +118,14 @@ lm78_remap(lm78_t *dev, uint8_t addr)
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
|
||||
dev->i2c_state = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -30,7 +30,7 @@
|
||||
|
||||
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, void *priv);
|
||||
void (*stop)(void *bus, uint8_t addr, void *priv);
|
||||
@@ -84,16 +84,43 @@ i2c_addbus(char *name)
|
||||
void
|
||||
i2c_removebus(void *bus_handle)
|
||||
{
|
||||
int c;
|
||||
i2c_t *p, *q;
|
||||
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
|
||||
|
||||
if (!bus_handle)
|
||||
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
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, 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_bus_t *bus = (i2c_bus_t *) bus_handle;
|
||||
|
||||
if (!bus_handle || ((base + size) >= NADDRS))
|
||||
if (!bus_handle || ((base + size) > NADDRS))
|
||||
return;
|
||||
|
||||
for (c = 0; c < size; c++) {
|
||||
@@ -133,7 +160,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size,
|
||||
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, 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_bus_t *bus = (i2c_bus_t *) bus_handle;
|
||||
|
||||
if (!bus_handle || ((base + size) >= NADDRS))
|
||||
if (!bus_handle || ((base + size) > NADDRS))
|
||||
return;
|
||||
|
||||
for (c = 0; c < size; c++) {
|
||||
@@ -152,7 +179,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
|
||||
continue;
|
||||
while(p) {
|
||||
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)
|
||||
p->prev->next = p->next;
|
||||
else
|
||||
@@ -173,7 +200,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
|
||||
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, 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
|
||||
i2c_start(void *bus_handle, uint8_t addr)
|
||||
uint8_t
|
||||
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_t *p;
|
||||
|
||||
if (!bus)
|
||||
return;
|
||||
return(ret);
|
||||
|
||||
p = bus->devices[addr];
|
||||
if (p) {
|
||||
while(p) {
|
||||
if (p->start) {
|
||||
p->start(bus_handle, addr, p->priv);
|
||||
ret |= p->start(bus_handle, addr, read, p->priv);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
while(p) {
|
||||
if (p->write) {
|
||||
ret = p->write(bus_handle, addr, data, p->priv);
|
||||
ret |= p->write(bus_handle, addr, data, p->priv);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
@@ -29,11 +29,11 @@ typedef struct {
|
||||
void *i2c;
|
||||
uint8_t addr, *data, writable;
|
||||
|
||||
uint16_t addr_mask, addr_register;
|
||||
uint8_t i2c_state;
|
||||
uint32_t addr_mask, addr_register;
|
||||
uint8_t addr_len, addr_pos;
|
||||
} i2c_eeprom_t;
|
||||
|
||||
#define ENABLE_I2C_EEPROM_LOG 1
|
||||
|
||||
#ifdef ENABLE_I2C_EEPROM_LOG
|
||||
int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG;
|
||||
|
||||
@@ -54,15 +54,17 @@ i2c_eeprom_log(const char *fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
i2c_eeprom_start(void *bus, uint8_t addr, void *priv)
|
||||
uint8_t
|
||||
i2c_eeprom_start(void *bus, uint8_t addr, uint8_t read, void *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_register = (addr << 8) & dev->addr_mask;
|
||||
dev->addr_pos = 0;
|
||||
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;
|
||||
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 */
|
||||
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;
|
||||
|
||||
if (dev->i2c_state == 0) {
|
||||
dev->i2c_state = 1;
|
||||
dev->addr_register = ((addr << 8) | data) & dev->addr_mask;
|
||||
i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register);
|
||||
if (dev->addr_pos < dev->addr_len) {
|
||||
dev->addr_register <<= 8;
|
||||
dev->addr_register |= data;
|
||||
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 {
|
||||
i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked");
|
||||
if (dev->writable)
|
||||
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)
|
||||
dev->data[dev->addr_register] = data;
|
||||
if (++dev->addr_register > dev->addr_mask) /* roll-over */
|
||||
dev->addr_register = 0;
|
||||
@@ -103,21 +109,24 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
|
||||
|
||||
|
||||
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));
|
||||
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->addr = addr;
|
||||
dev->data = data;
|
||||
dev->writable = writable;
|
||||
|
||||
dev->addr_len = (size >= 4096) ? 16 : 8; /* use 16-bit addresses on 24C32 and above */
|
||||
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;
|
||||
}
|
||||
@@ -128,9 +137,9 @@ i2c_eeprom_close(void *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);
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@ enum {
|
||||
I2C_TRANSMIT_START,
|
||||
I2C_TRANSMIT,
|
||||
I2C_ACKNOWLEDGE,
|
||||
I2C_NEGACKNOWLEDGE,
|
||||
I2C_TRANSACKNOWLEDGE,
|
||||
I2C_TRANSMIT_WAIT
|
||||
};
|
||||
@@ -55,7 +56,7 @@ typedef struct {
|
||||
char *bus_name;
|
||||
void *i2c;
|
||||
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;
|
||||
|
||||
|
||||
@@ -113,11 +114,11 @@ void
|
||||
i2c_gpio_next_byte(i2c_gpio_t *dev)
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint8_t i;
|
||||
@@ -126,19 +127,20 @@ i2c_gpio_write(i2c_gpio_t *dev)
|
||||
case SLAVE_IDLE:
|
||||
i = dev->slave_addr;
|
||||
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)) {
|
||||
dev->slave_state = SLAVE_INVALID;
|
||||
break;
|
||||
dev->slave_addr = 0xff;
|
||||
return I2C_NEGACKNOWLEDGE;
|
||||
}
|
||||
|
||||
if (i == 0xff)
|
||||
i2c_start(dev->i2c, dev->slave_addr);
|
||||
if (i == 0xff) /* start only once per transfer */
|
||||
i2c_start(dev->i2c, dev->slave_addr, dev->slave_read);
|
||||
|
||||
if (dev->slave_rw) {
|
||||
if (dev->slave_read) {
|
||||
dev->slave_state = SLAVE_SENDDATA;
|
||||
dev->transmit = TRANSMITTER_SLAVE;
|
||||
dev->byte = i2c_read(dev->i2c, dev->slave_addr);
|
||||
@@ -150,15 +152,22 @@ i2c_gpio_write(i2c_gpio_t *dev)
|
||||
|
||||
case SLAVE_RECEIVEADDR:
|
||||
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_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
|
||||
dev->slave_state = dev->slave_read ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
|
||||
if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte))
|
||||
return I2C_NEGACKNOWLEDGE;
|
||||
break;
|
||||
|
||||
case SLAVE_RECEIVEDATA:
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
dev->slave_addr = 0xff;
|
||||
@@ -183,8 +192,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
|
||||
switch (dev->state) {
|
||||
case I2C_IDLE:
|
||||
/* !dev->scl check breaks NCR SDMS. */
|
||||
if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */
|
||||
/* dev->scl check breaks NCR SDMS. */
|
||||
if (scl && dev->last_sda && !sda) { /* start bit */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name);
|
||||
dev->state = I2C_RECEIVE;
|
||||
dev->pos = 0;
|
||||
@@ -203,10 +212,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
dev->byte |= 1;
|
||||
else
|
||||
dev->byte &= 0xfe;
|
||||
if (++dev->pos == 8) {
|
||||
i2c_gpio_write(dev);
|
||||
dev->state = I2C_ACKNOWLEDGE;
|
||||
}
|
||||
if (++dev->pos == 8)
|
||||
dev->state = i2c_gpio_write(dev);
|
||||
} else if (dev->scl && scl) {
|
||||
if (sda && !dev->last_sda) { /* stop bit */
|
||||
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:
|
||||
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;
|
||||
dev->pos = 0;
|
||||
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
|
||||
}
|
||||
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:
|
||||
if (!dev->scl && scl) {
|
||||
if (sda) { /* not acknowledged; must be end of transfer */
|
||||
@@ -306,12 +323,17 @@ uint8_t
|
||||
i2c_gpio_get_sda(void *dev_handle)
|
||||
{
|
||||
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
|
||||
if ((dev->state == I2C_TRANSMIT) || (dev->state == I2C_ACKNOWLEDGE))
|
||||
return dev->sda;
|
||||
else if (dev->state == I2C_RECEIVE_WAIT)
|
||||
return 0; /* ack */
|
||||
else
|
||||
return 1;
|
||||
switch (dev->state) {
|
||||
case I2C_TRANSMIT:
|
||||
case I2C_ACKNOWLEDGE:
|
||||
return dev->sda;
|
||||
|
||||
case I2C_RECEIVE_WAIT:
|
||||
return 0; /* ack */
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -98,95 +98,189 @@ static void
|
||||
smbus_piix4_write(uint16_t addr, uint8_t val, void *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);
|
||||
|
||||
prev_stat = dev->next_stat;
|
||||
dev->next_stat = 0;
|
||||
dev->next_stat = 0x00;
|
||||
switch (addr - dev->io_base) {
|
||||
case 0x00:
|
||||
/* some status bits are reset by writing 1 to them */
|
||||
for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) {
|
||||
for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */
|
||||
if (val & smbus_addr)
|
||||
dev->stat &= ~smbus_addr;
|
||||
}
|
||||
break;
|
||||
|
||||
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 */
|
||||
/* cancel only if a command is in progress */
|
||||
if (prev_stat) {
|
||||
dev->stat = 0x10; /* raise FAILED */
|
||||
if (prev_stat) { /* cancel only if a command is in progress */
|
||||
timer_disable(&dev->response_timer);
|
||||
dev->stat = 0x10; /* raise FAILED */
|
||||
}
|
||||
}
|
||||
if (val & 0x40) { /* dispatch command if START is set */
|
||||
timer_bytes++; /* address */
|
||||
|
||||
smbus_addr = (dev->addr >> 1);
|
||||
if (!i2c_has_device(i2c_smbus, smbus_addr)) {
|
||||
/* raise DEV_ERR if no device is at this address */
|
||||
dev->next_stat = 0x4;
|
||||
read = dev->addr & 0x01;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
smbus_read = dev->addr & 0x01;
|
||||
|
||||
/* start transaction */
|
||||
i2c_start(i2c_smbus, smbus_addr);
|
||||
dev->next_stat = 0x02; /* raise INTER (command completed) by default */
|
||||
|
||||
/* decode the 3-bit command protocol */
|
||||
dev->next_stat = 0x2; /* raise INTER (command completed) by default */
|
||||
switch ((val >> 2) & 0x7) {
|
||||
/* Decode the command protocol.
|
||||
VIA-specific modes (0x4 and [0x6:0xf]) are undocumented and required real hardware research. */
|
||||
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 */
|
||||
break;
|
||||
|
||||
case 0x1: /* byte R/W */
|
||||
if (smbus_read)
|
||||
if (read) /* byte read */
|
||||
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
|
||||
else
|
||||
else /* byte write */
|
||||
i2c_write(i2c_smbus, smbus_addr, dev->data0);
|
||||
timer_bytes++;
|
||||
|
||||
break;
|
||||
|
||||
case 0x2: /* byte data R/W */
|
||||
/* command write */
|
||||
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);
|
||||
else
|
||||
else /* byte write */
|
||||
i2c_write(i2c_smbus, smbus_addr, dev->data0);
|
||||
timer_bytes++;
|
||||
|
||||
break;
|
||||
|
||||
case 0x3: /* word data R/W */
|
||||
/* command write */
|
||||
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->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->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;
|
||||
|
||||
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);
|
||||
/* SMBus block data is preceded by a length */
|
||||
if (smbus_read) {
|
||||
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
|
||||
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++)
|
||||
dev->data[smbus_read] = i2c_read(i2c_smbus, smbus_addr);
|
||||
timer_bytes++;
|
||||
|
||||
if (read) {
|
||||
/* block read [data0] (I2C) or [first byte] (SMBus) bytes */
|
||||
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 {
|
||||
i2c_write(i2c_smbus, smbus_addr, dev->data0);
|
||||
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++)
|
||||
i2c_write(i2c_smbus, smbus_addr, dev->data[smbus_read]);
|
||||
block_len = dev->data0;
|
||||
if (cmd == 0x5) /* send length [data0] as first byte on SMBus */
|
||||
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;
|
||||
|
||||
default:
|
||||
/* other command protocols have undefined behavior, but raise DEV_ERR to be safe */
|
||||
dev->next_stat = 0x4;
|
||||
case 0x6: /* I2C with 10-bit address */
|
||||
if (dev->local != SMBUS_VIA) /* VIA only */
|
||||
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;
|
||||
}
|
||||
|
||||
/* stop transaction */
|
||||
/* Finish transfer. */
|
||||
i2c_stop(i2c_smbus, smbus_addr);
|
||||
}
|
||||
break;
|
||||
@@ -214,11 +308,11 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
/* if a status register update was given, dispatch it after 10us to ensure nothing breaks */
|
||||
if (dev->next_stat) {
|
||||
dev->stat = 0x1; /* raise HOST_BUSY while waiting */
|
||||
if (dev->next_stat) { /* schedule dispatch of any pending status register update */
|
||||
dev->stat = 0x01; /* raise HOST_BUSY while waiting */
|
||||
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;
|
||||
|
||||
/* dispatch the status register update */
|
||||
/* Dispatch the status register update. */
|
||||
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));
|
||||
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);
|
||||
|
||||
@@ -277,7 +372,16 @@ smbus_piix4_close(void *priv)
|
||||
const device_t piix4_smbus_device = {
|
||||
"PIIX4-compatible SMBus Host Controller",
|
||||
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,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
|
@@ -25,36 +25,37 @@ extern void *i2c_smbus;
|
||||
/* i2c.c */
|
||||
extern void *i2c_addbus(char *name);
|
||||
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,
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
|
||||
void (*stop)(void *bus, uint8_t addr, void *priv),
|
||||
void *priv);
|
||||
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
|
||||
void (*stop)(void *bus, uint8_t addr, void *priv),
|
||||
void *priv);
|
||||
|
||||
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 (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
|
||||
void (*stop)(void *bus, uint8_t addr, void *priv),
|
||||
void *priv);
|
||||
|
||||
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_write(void *bus_handle, uint8_t addr, uint8_t data);
|
||||
extern void i2c_stop(void *bus_handle, uint8_t addr);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* i2c_gpio.c */
|
||||
|
@@ -19,15 +19,20 @@
|
||||
|
||||
|
||||
#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;
|
||||
uint8_t stat, next_stat, ctl, cmd, addr,
|
||||
data0, data1,
|
||||
index,
|
||||
data[SMBUS_PIIX4_BLOCK_DATA_SIZE];
|
||||
index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE];
|
||||
pc_timer_t response_timer;
|
||||
void *i2c;
|
||||
} 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
|
||||
extern const device_t piix4_smbus_device;
|
||||
extern const device_t via_smbus_device;
|
||||
#endif
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user