I2C overhaul part 3: "we finally figured out NCR NVRAM" edition
This commit is contained in:
@@ -103,13 +103,16 @@ gl518sm_i2c_read(void *bus, uint8_t addr, void *priv)
|
||||
uint16_t read = gl518sm_read(dev, dev->addr_register);
|
||||
uint8_t ret = 0;
|
||||
|
||||
if (dev->i2c_state == 0)
|
||||
dev->i2c_state = 1;
|
||||
|
||||
if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */
|
||||
dev->i2c_state = 2;
|
||||
ret = read >> 8;
|
||||
} else
|
||||
} else {
|
||||
ret = read;
|
||||
|
||||
dev->addr_register++;
|
||||
dev->addr_register++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -178,6 +181,7 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
|
||||
break;
|
||||
|
||||
default:
|
||||
dev->i2c_state = 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ 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);
|
||||
|
||||
|
||||
#define ENABLE_LM75_LOG 1
|
||||
#ifdef ENABLE_LM75_LOG
|
||||
int lm75_do_log = ENABLE_LM75_LOG;
|
||||
|
||||
@@ -86,23 +86,39 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv)
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
uint8_t ret = 0;
|
||||
|
||||
switch (dev->addr_register & 0x3) {
|
||||
case 0x0: /* temperature */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0);
|
||||
break;
|
||||
if (dev->i2c_state == 0)
|
||||
dev->i2c_state = 1;
|
||||
|
||||
case 0x1: /* configuration */
|
||||
ret = lm75_read(dev, 0x2);
|
||||
break;
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
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_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);
|
||||
} else {
|
||||
switch (dev->addr_register & 0x3) {
|
||||
case 0x0: /* temperature */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x0 : 0x1);
|
||||
break;
|
||||
|
||||
case 0x2: /* Thyst */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3);
|
||||
break;
|
||||
case 0x3: /* Tos */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5);
|
||||
break;
|
||||
case 0x1: /* configuration */
|
||||
ret = lm75_read(dev, 0x2);
|
||||
break;
|
||||
|
||||
case 0x2: /* Thyst */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x3 : 0x4);
|
||||
break;
|
||||
case 0x3: /* Tos */
|
||||
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x5 : 0x6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (++dev->i2c_state > 2)
|
||||
dev->i2c_state = 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -112,15 +128,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
to access some of its proprietary registers. Pass this operation on to
|
||||
the main monitor address through an internal I2C call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
|
||||
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
|
||||
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
|
||||
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
|
||||
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
|
||||
} else if ((reg & 0x7) == 0x0) /* temperature high byte */
|
||||
if ((reg & 0x7) == 0x0) /* temperature high byte */
|
||||
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
|
||||
else if ((reg & 0x7) == 0x1) /* temperature low byte */
|
||||
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
|
||||
@@ -145,23 +153,37 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (dev->addr_register & 0x3) {
|
||||
case 0x0: /* temperature */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data);
|
||||
break;
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
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_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);
|
||||
return 1;
|
||||
} else {
|
||||
switch (dev->addr_register & 0x3) {
|
||||
case 0x0: /* temperature */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x0 : 0x1, data);
|
||||
break;
|
||||
|
||||
case 0x1: /* configuration */
|
||||
lm75_write(dev, 0x2, data);
|
||||
break;
|
||||
case 0x1: /* configuration */
|
||||
lm75_write(dev, 0x2, data);
|
||||
break;
|
||||
|
||||
case 0x2: /* Thyst */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data);
|
||||
break;
|
||||
case 0x3: /* Tos */
|
||||
lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data);
|
||||
break;
|
||||
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)
|
||||
dev->i2c_state = 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -171,17 +193,6 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
lm75_log("LM75: write(%02X, %02X)\n", reg, val);
|
||||
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
to access some of its proprietary registers. Pass this operation on to
|
||||
the main monitor address through an internal I2C call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
|
||||
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
|
||||
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
|
||||
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val);
|
||||
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t reg_idx = (reg & 0x7);
|
||||
|
||||
if ((reg_idx <= 0x1) || (reg_idx == 0x7))
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -194,6 +194,8 @@ i2c_has_device(void *bus_handle, uint8_t addr)
|
||||
if (!bus)
|
||||
return 0;
|
||||
|
||||
i2c_log("I2C: has_device(%s, %02X) = %d\n", bus->name, addr, !!bus->devices[addr]);
|
||||
|
||||
return(!!bus->devices[addr]);
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of the AT24Cxx series of I2C EEPROMs.
|
||||
* Emulation of the 24Cxx series of I2C EEPROMs.
|
||||
*
|
||||
*
|
||||
*
|
||||
@@ -27,22 +27,42 @@
|
||||
|
||||
typedef struct {
|
||||
void *i2c;
|
||||
uint8_t addr;
|
||||
uint8_t *data;
|
||||
uint8_t writable;
|
||||
uint8_t addr, *data, writable;
|
||||
|
||||
uint16_t addr_mask;
|
||||
uint8_t addr_register;
|
||||
uint16_t addr_mask, addr_register;
|
||||
uint8_t i2c_state;
|
||||
} i2c_eeprom_t;
|
||||
|
||||
#define ENABLE_I2C_EEPROM_LOG 1
|
||||
#ifdef ENABLE_I2C_EEPROM_LOG
|
||||
int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG;
|
||||
|
||||
|
||||
static void
|
||||
i2c_eeprom_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (i2c_eeprom_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define i2c_eeprom_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
i2c_eeprom_start(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
|
||||
|
||||
i2c_eeprom_log("I2C EEPROM: start()\n");
|
||||
|
||||
dev->i2c_state = 0;
|
||||
dev->addr_register = (addr << 8) & dev->addr_mask;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +70,13 @@ uint8_t
|
||||
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];
|
||||
|
||||
return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask];
|
||||
i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret);
|
||||
if (++dev->addr_register > dev->addr_mask) /* roll-over */
|
||||
dev->addr_register = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +87,16 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
|
||||
|
||||
if (dev->i2c_state == 0) {
|
||||
dev->i2c_state = 1;
|
||||
dev->addr_register = data;
|
||||
} else if (dev->writable)
|
||||
dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data;
|
||||
else
|
||||
return 0;
|
||||
dev->addr_register = ((addr << 8) | data) & dev->addr_mask;
|
||||
i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register);
|
||||
} else {
|
||||
i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked");
|
||||
if (dev->writable)
|
||||
dev->data[dev->addr_register] = data;
|
||||
if (++dev->addr_register > dev->addr_mask) /* roll-over */
|
||||
dev->addr_register = 0;
|
||||
return dev->writable;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -78,6 +108,8 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t w
|
||||
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);
|
||||
|
||||
dev->i2c = i2c;
|
||||
dev->addr = addr;
|
||||
dev->data = data;
|
||||
@@ -96,6 +128,8 @@ i2c_eeprom_close(void *dev_handle)
|
||||
{
|
||||
i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle;
|
||||
|
||||
i2c_eeprom_log("I2C EEPROM: close()\n");
|
||||
|
||||
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);
|
||||
|
||||
free(dev);
|
||||
|
@@ -52,19 +52,43 @@ enum {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *bus_name;
|
||||
void *i2c;
|
||||
uint8_t scl, sda, state, slave_state, slave_addr,
|
||||
slave_rw, last_sda, pos, transmit, byte;
|
||||
} i2c_gpio_t;
|
||||
|
||||
|
||||
#ifdef ENABLE_I2C_GPIO_LOG
|
||||
int i2c_gpio_do_log = ENABLE_I2C_GPIO_LOG;
|
||||
|
||||
|
||||
static void
|
||||
i2c_gpio_log(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (i2c_gpio_do_log >= level) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define i2c_gpio_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
void *
|
||||
i2c_gpio_init(char *bus_name)
|
||||
{
|
||||
i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t));
|
||||
memset(dev, 0, sizeof(i2c_gpio_t));
|
||||
|
||||
dev->i2c = i2c_addbus(bus_name);
|
||||
i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name);
|
||||
|
||||
dev->bus_name = bus_name;
|
||||
dev->i2c = i2c_addbus(dev->bus_name);
|
||||
dev->scl = dev->sda = 1;
|
||||
dev->slave_addr = 0xff;
|
||||
|
||||
@@ -77,6 +101,8 @@ i2c_gpio_close(void *dev_handle)
|
||||
{
|
||||
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
|
||||
|
||||
i2c_gpio_log(1, "I2C GPIO %s: close()\n", dev->bus_name);
|
||||
|
||||
i2c_removebus(dev->i2c);
|
||||
|
||||
free(dev);
|
||||
@@ -87,6 +113,7 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +128,8 @@ i2c_gpio_write(i2c_gpio_t *dev)
|
||||
dev->slave_addr = dev->byte >> 1;
|
||||
dev->slave_rw = 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);
|
||||
|
||||
if (!i2c_has_device(dev->i2c, dev->slave_addr)) {
|
||||
dev->slave_state = SLAVE_INVALID;
|
||||
break;
|
||||
@@ -120,11 +149,13 @@ i2c_gpio_write(i2c_gpio_t *dev)
|
||||
break;
|
||||
|
||||
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;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@@ -134,7 +165,10 @@ i2c_gpio_write(i2c_gpio_t *dev)
|
||||
void
|
||||
i2c_gpio_stop(i2c_gpio_t *dev)
|
||||
{
|
||||
i2c_stop(dev->i2c, dev->slave_addr);
|
||||
i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name);
|
||||
|
||||
if (dev->slave_addr != 0xff)
|
||||
i2c_stop(dev->i2c, dev->slave_addr);
|
||||
|
||||
dev->slave_addr = 0xff;
|
||||
dev->slave_state = SLAVE_IDLE;
|
||||
@@ -149,7 +183,9 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
|
||||
switch (dev->state) {
|
||||
case I2C_IDLE:
|
||||
if (dev->scl && scl && dev->last_sda && !sda) { /* start bit */
|
||||
/* !dev->scl check breaks NCR SDMS. */
|
||||
if (/*!dev->scl &&*/ 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;
|
||||
}
|
||||
@@ -173,9 +209,11 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
}
|
||||
} 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);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
} else if (!sda && dev->last_sda) { /* start bit */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from RECEIVE)\n", dev->bus_name);
|
||||
dev->pos = 0;
|
||||
dev->slave_state = SLAVE_IDLE;
|
||||
}
|
||||
@@ -184,6 +222,7 @@ 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);
|
||||
sda = 0;
|
||||
dev->pos = 0;
|
||||
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
|
||||
@@ -193,12 +232,14 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
case I2C_TRANSACKNOWLEDGE:
|
||||
if (!dev->scl && scl) {
|
||||
if (sda) { /* not acknowledged; must be end of transfer */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: End of transfer\n", dev->bus_name);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
} else { /* next byte to transfer */
|
||||
dev->state = I2C_TRANSMIT_START;
|
||||
i2c_gpio_next_byte(dev);
|
||||
dev->pos = 0;
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -208,8 +249,10 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
if (dev->last_sda && !sda) { /* start bit */
|
||||
i2c_gpio_next_byte(dev);
|
||||
dev->pos = 0;
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
|
||||
}
|
||||
if (!dev->last_sda && sda) { /* stop bit */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_WAIT)\n", dev->bus_name);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
}
|
||||
@@ -220,6 +263,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
if (!dev->scl && scl)
|
||||
dev->state = I2C_TRANSMIT;
|
||||
if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_START)\n", dev->bus_name);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
}
|
||||
@@ -228,13 +272,18 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
case I2C_TRANSMIT:
|
||||
if (!dev->scl && scl) {
|
||||
dev->scl = scl;
|
||||
if (!dev->pos)
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Transmit byte %02X\n", dev->bus_name, dev->byte);
|
||||
dev->sda = sda = dev->byte & 0x80;
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Transmit bit %02X %d\n", dev->bus_name, dev->byte, dev->pos);
|
||||
dev->byte <<= 1;
|
||||
dev->pos++;
|
||||
return;
|
||||
}
|
||||
if (dev->scl && !scl && (dev->pos == 8))
|
||||
if (dev->scl && !scl && (dev->pos == 8)) {
|
||||
dev->state = I2C_TRANSACKNOWLEDGE;
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Acknowledge mode\n", dev->bus_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include <86box/device.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/scsi.h>
|
||||
#include <86box/scsi_device.h>
|
||||
#include <86box/scsi_ncr53c8xx.h>
|
||||
@@ -225,14 +226,8 @@ typedef struct {
|
||||
int msg_action;
|
||||
int msg_len;
|
||||
uint8_t msg[NCR_MAX_MSGIN_LEN];
|
||||
#ifdef USE_NVRAM
|
||||
uint16_t nvram;
|
||||
uint8_t nvram_t;
|
||||
uint8_t nvram_op;
|
||||
uint8_t nvram_param;
|
||||
uint8_t nvram_start;
|
||||
uint8_t nvram_index;
|
||||
#endif
|
||||
uint8_t nvram[2048]; /* 24C16 EEPROM (16 kbit) */
|
||||
void *i2c, *eeprom;
|
||||
uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */
|
||||
/* 0 if SCRIPTS are running or stopped.
|
||||
* 1 if a Wait Reselect instruction has been issued.
|
||||
@@ -434,10 +429,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev)
|
||||
dev->gpreg = 0;
|
||||
dev->slpar = 0;
|
||||
dev->sstop = 1;
|
||||
dev->gpcntl = 0x0f;
|
||||
#ifdef USE_NVRAM
|
||||
dev->nvram_t = dev->nvram_index = 0;
|
||||
#endif
|
||||
dev->gpcntl = 0x03;
|
||||
|
||||
if (dev->chip >= CHIP_825) {
|
||||
/* This *IS* a wide SCSI controller, so reset all SCSI
|
||||
@@ -474,7 +466,7 @@ ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len)
|
||||
buf[i] = inb((uint16_t) (addr + i));
|
||||
} else {
|
||||
ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr);
|
||||
dma_bm_read(addr, buf, len, 4);
|
||||
dma_bm_read(addr, buf, len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +484,7 @@ ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len)
|
||||
outb((uint16_t) (addr + i), buf[i]);
|
||||
} else {
|
||||
ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr);
|
||||
dma_bm_write(addr, buf, len, 4);
|
||||
dma_bm_write(addr, buf, len, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,10 +503,10 @@ static
|
||||
void do_irq(ncr53c8xx_t *dev, int level)
|
||||
{
|
||||
if (level) {
|
||||
pci_set_irq(dev->pci_slot, PCI_INTA);
|
||||
pci_set_irq(dev->pci_slot, PCI_INTA);
|
||||
ncr53c8xx_log("Raising IRQ...\n");
|
||||
} else {
|
||||
pci_clear_irq(dev->pci_slot, PCI_INTA);
|
||||
pci_clear_irq(dev->pci_slot, PCI_INTA);
|
||||
ncr53c8xx_log("Lowering IRQ...\n");
|
||||
}
|
||||
}
|
||||
@@ -852,8 +844,8 @@ ncr53c8xx_do_msgin(ncr53c8xx_t *dev)
|
||||
switch to PHASE_MO. */
|
||||
switch (dev->msg_action) {
|
||||
case 0:
|
||||
ncr53c8xx_set_phase(dev, PHASE_CMD);
|
||||
break;
|
||||
ncr53c8xx_set_phase(dev, PHASE_CMD);
|
||||
break;
|
||||
case 1:
|
||||
ncr53c8xx_disconnect(dev);
|
||||
break;
|
||||
@@ -1444,7 +1436,7 @@ ncr53c8xx_callback(void *p)
|
||||
if (dev->waiting)
|
||||
timer_on_auto(&dev->timer, 40.0);
|
||||
else
|
||||
ncr53c8xx_process_script(dev);
|
||||
ncr53c8xx_process_script(dev);
|
||||
}
|
||||
|
||||
if (dev->sstop)
|
||||
@@ -1452,146 +1444,22 @@ ncr53c8xx_callback(void *p)
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_NVRAM
|
||||
static void
|
||||
ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save)
|
||||
ncr53c8xx_eeprom(ncr53c8xx_t *dev, uint8_t save)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (save)
|
||||
f = nvr_fopen(dev->nvr_path, L"wb");
|
||||
else
|
||||
f = nvr_fopen(dev->nvr_path, L"rb");
|
||||
if (f)
|
||||
{
|
||||
if (save) {
|
||||
fwrite((uint8_t *) &dev->nvram, 1, 1, f);
|
||||
fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
|
||||
} else {
|
||||
fread((uint8_t *) &dev->nvram, 1, 1, f);
|
||||
fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
|
||||
}
|
||||
f = nvr_fopen(dev->nvr_path, save ? L"wb": L"rb");
|
||||
if (f) {
|
||||
if (save)
|
||||
fwrite(&dev->nvram, sizeof(dev->nvram), 1, f);
|
||||
else
|
||||
fread(&dev->nvram, sizeof(dev->nvram), 1, f);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define ADDRESS_LENGTH 9
|
||||
#define ADDRESS_END (ADDRESS_LENGTH + 2)
|
||||
#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2)
|
||||
#define ADDRESS_MASK 0x3f
|
||||
#define DATA_LENGTH 8
|
||||
#define DATA_START (ADDRESS_END + 1)
|
||||
#define DATA_END (ADDRESS_END + DATA_LENGTH)
|
||||
|
||||
|
||||
static void
|
||||
ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val)
|
||||
{
|
||||
uint8_t temp, old = dev->nvram_t;
|
||||
dev->nvram_t = val & 0x03;
|
||||
|
||||
if (val & 0x02) {
|
||||
if (!dev->nvram_index) {
|
||||
/* First signal clocked in after clock is high, start bit. */
|
||||
dev->nvram_start = 1;
|
||||
ncr53c8xx_log("[W] Serial EEPROM: Start bit\n");
|
||||
dev->nvram_op = 0;
|
||||
} else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) {
|
||||
if (!dev->nvram_start)
|
||||
return;
|
||||
|
||||
dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1);
|
||||
if (dev->nvram_index == 2) {
|
||||
// ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op);
|
||||
dev->nvram_param = 0;
|
||||
}
|
||||
} else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) {
|
||||
if (!dev->nvram_start)
|
||||
return;
|
||||
|
||||
dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3);
|
||||
if (dev->nvram_index < ADDRESS_END) {
|
||||
dev->nvram_index++;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->nvram_op) {
|
||||
case 0x00:
|
||||
temp = dev->nvram_param >> ADDRESS_SHIFT;
|
||||
switch(temp) {
|
||||
case 0x00:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: EWDS\n");
|
||||
break;
|
||||
case 0x01:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: WRAL\n");
|
||||
break;
|
||||
case 0x02:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: ERAL\n");
|
||||
break;
|
||||
case 0x03:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: EWEN\n");
|
||||
break;
|
||||
default:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n");
|
||||
break;
|
||||
}
|
||||
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
|
||||
return;
|
||||
case 0x01:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: WRITE\n");
|
||||
break;
|
||||
case 0x02:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: READ\n");
|
||||
break;
|
||||
case 0x03:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: ERASE\n");
|
||||
break;
|
||||
default:
|
||||
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
} else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
|
||||
if (!dev->nvram_start)
|
||||
return;
|
||||
|
||||
if (dev->nvram_index == DATA_END) {
|
||||
ncr53c8xx_log("[W] Serial EEPROM: Data end\n");
|
||||
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dev->nvram_index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev)
|
||||
{
|
||||
uint8_t temp = 0;
|
||||
|
||||
if (dev->gpreg & 0x02) {
|
||||
if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
|
||||
if (!dev->nvram_start)
|
||||
return temp;
|
||||
|
||||
dev->nvram_index++;
|
||||
|
||||
if (dev->nvram_index == DATA_END) {
|
||||
ncr53c8xx_log("[R] Serial EEPROM: Data end\n");
|
||||
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
|
||||
{
|
||||
@@ -1659,12 +1527,8 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
|
||||
break;
|
||||
case 0x07: /* GPREG */
|
||||
ncr53c8xx_log("NCR 810: GPREG write %02X\n", val);
|
||||
tmp = dev->gpreg;
|
||||
dev->gpreg = val & 0xfe;
|
||||
#ifdef USE_NVRAM
|
||||
if ((dev->gpcntl & 0xc3) == 0x00)
|
||||
ncr53c8xx_serial_eeprom_write(dev, val & 0x03);
|
||||
#endif
|
||||
dev->gpreg = val;
|
||||
i2c_gpio_set(dev->i2c, !!(dev->gpreg & 0x02), !!(dev->gpreg & 0x01));
|
||||
break;
|
||||
case 0x08: /* SFBR */
|
||||
/* The CPU is not allowed to write to this register. However the
|
||||
@@ -1893,13 +1757,18 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset)
|
||||
ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid);
|
||||
return dev->sdid;
|
||||
case 0x07: /* GPREG */
|
||||
#ifdef USE_NVRAM
|
||||
tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e;
|
||||
if ((dev->gpcntl & 0xc3) == 0x01)
|
||||
tmp |= ncr53c8xx_serial_eeprom_read(dev);
|
||||
#else
|
||||
tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01;
|
||||
#endif
|
||||
tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1f;
|
||||
if ((dev->gpcntl & 0x41) == 0x01) {
|
||||
tmp &= 0xfe;
|
||||
if (i2c_gpio_get_sda(dev->i2c))
|
||||
tmp |= 0x01;
|
||||
}
|
||||
if ((dev->gpcntl & 0x82) == 0x02) {
|
||||
tmp &= 0xfd;
|
||||
if (i2c_gpio_get_scl(dev->i2c))
|
||||
tmp |= 0x02;
|
||||
}
|
||||
|
||||
ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp);
|
||||
return tmp;
|
||||
case 0x08: /* Revision ID */
|
||||
@@ -2677,8 +2546,8 @@ ncr53c8xx_init(const device_t *info)
|
||||
dev->chip_rev = 0x26;
|
||||
dev->nvr_path = L"ncr53c825a.nvr";
|
||||
}
|
||||
ncr53c8xx_pci_bar[2].addr_regs[0] = 0;
|
||||
ncr53c8xx_pci_bar[3].addr = 0xffff0000;
|
||||
ncr53c8xx_pci_bar[2].addr_regs[0] = 0;
|
||||
ncr53c8xx_pci_bar[3].addr = 0xffff0000;
|
||||
/* Need to make it align on a 16k boundary as that's this emulator's
|
||||
memory mapping granularity. */
|
||||
ncr53c8xx_ram_init(dev, 0x0fffc000);
|
||||
@@ -2695,10 +2564,11 @@ ncr53c8xx_init(const device_t *info)
|
||||
dev->nvr_path = L"ncr53c810.nvr";
|
||||
}
|
||||
|
||||
#ifdef USE_NVRAM
|
||||
dev->i2c = i2c_gpio_init("nvr_ncr53c8xx");
|
||||
dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->nvram, sizeof(dev->nvram), 1);
|
||||
|
||||
/* Load the serial EEPROM. */
|
||||
ncr53c8xx_eeprom(dev, 0);
|
||||
#endif
|
||||
|
||||
ncr53c8xx_soft_reset(dev);
|
||||
|
||||
@@ -2714,6 +2584,15 @@ ncr53c8xx_close(void *priv)
|
||||
ncr53c8xx_t *dev = (ncr53c8xx_t *)priv;
|
||||
|
||||
if (dev) {
|
||||
/* Save the serial EEPROM. */
|
||||
ncr53c8xx_eeprom(dev, 1);
|
||||
|
||||
if (dev->eeprom)
|
||||
i2c_eeprom_close(dev->eeprom);
|
||||
|
||||
if (dev->i2c)
|
||||
i2c_gpio_close(dev->i2c);
|
||||
|
||||
free(dev);
|
||||
dev = NULL;
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ static uint8_t edid_data[128] = {
|
||||
0x08, /* Analog input, separate sync */
|
||||
34, 0, /* Landscape, 4:3 */
|
||||
0, /* Gamma */
|
||||
0x08, /* RGB colour */
|
||||
0x08, /* RGB color */
|
||||
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */
|
||||
|
||||
0xff, 0xff, 0xff, /* Established timing bitmap */
|
||||
|
Reference in New Issue
Block a user