I2C overhaul part 6: making DDC actually work
This commit is contained in:
@@ -126,7 +126,7 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t w
|
||||
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 >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
|
||||
i2c_sethandler(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);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ enum {
|
||||
typedef struct {
|
||||
char *bus_name;
|
||||
void *i2c;
|
||||
uint8_t scl, sda, state, slave_state, slave_addr,
|
||||
uint8_t scl, sda, receive_wait_sda, state, slave_state, slave_addr,
|
||||
slave_read, last_sda, pos, transmit, byte;
|
||||
} i2c_gpio_t;
|
||||
|
||||
@@ -188,11 +188,12 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
{
|
||||
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
|
||||
|
||||
i2c_gpio_log(3, "I2C GPIO %s: scl=%d->%d sda=%d->%d last_valid_sda=%d state=%d\n", dev->bus_name, dev->scl, scl, dev->last_sda, sda, dev->sda, dev->state);
|
||||
|
||||
switch (dev->state) {
|
||||
case I2C_IDLE:
|
||||
/* 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);
|
||||
if (scl && dev->last_sda && !sda) { /* start condition; dev->scl check breaks NCR SDMS */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Start condition received (from IDLE)\n", dev->bus_name);
|
||||
dev->state = I2C_RECEIVE;
|
||||
dev->pos = 0;
|
||||
}
|
||||
@@ -201,6 +202,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
case I2C_RECEIVE_WAIT:
|
||||
if (!dev->scl && scl)
|
||||
dev->state = I2C_RECEIVE;
|
||||
else if (!dev->scl && !scl && dev->last_sda && sda) /* workaround for repeated start condition on Windows XP DDC */
|
||||
dev->receive_wait_sda = 1;
|
||||
/* fall-through */
|
||||
|
||||
case I2C_RECEIVE:
|
||||
@@ -213,12 +216,12 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
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);
|
||||
if (sda && !dev->last_sda) { /* stop condition */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Stop condition 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);
|
||||
} else if (!sda && dev->last_sda) { /* start condition */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Start condition received (from RECEIVE)\n", dev->bus_name);
|
||||
dev->pos = 0;
|
||||
dev->slave_state = SLAVE_IDLE;
|
||||
}
|
||||
@@ -229,6 +232,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
if (!dev->scl && scl) {
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer to %02X\n", dev->bus_name, dev->slave_addr);
|
||||
sda = 0;
|
||||
dev->receive_wait_sda = 0; /* ack */
|
||||
dev->pos = 0;
|
||||
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
|
||||
}
|
||||
@@ -261,13 +265,13 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
|
||||
case I2C_TRANSMIT_WAIT:
|
||||
if (dev->scl && scl) {
|
||||
if (dev->last_sda && !sda) { /* start bit */
|
||||
if (dev->last_sda && !sda) { /* start condition */
|
||||
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);
|
||||
if (!dev->last_sda && sda) { /* stop condition */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Stop condition received (from TRANSMIT_WAIT)\n", dev->bus_name);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
}
|
||||
@@ -277,8 +281,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
|
||||
case I2C_TRANSMIT_START:
|
||||
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);
|
||||
if (dev->scl && scl && !dev->last_sda && sda) { /* stop condition */
|
||||
i2c_gpio_log(2, "I2C GPIO %s: Stop condition received (from TRANSMIT_START)\n", dev->bus_name);
|
||||
dev->state = I2C_IDLE;
|
||||
i2c_gpio_stop(dev);
|
||||
}
|
||||
@@ -327,7 +331,7 @@ i2c_gpio_get_sda(void *dev_handle)
|
||||
return dev->sda;
|
||||
|
||||
case I2C_RECEIVE_WAIT:
|
||||
return 0; /* ack */
|
||||
return dev->receive_wait_sda;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
|
@@ -186,47 +186,6 @@ write_fifo(serial_t *dev, uint8_t dat)
|
||||
}
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <86box/pit.h>
|
||||
HANDLE serialdbg = NULL;
|
||||
OVERLAPPED serialdbgoverlapped_r;
|
||||
OVERLAPPED serialdbgoverlapped_w;
|
||||
uint8_t serialdbg_reading = 0;
|
||||
DWORD serialdbg_read;
|
||||
uint8_t serialdbg_buf[1];
|
||||
pc_timer_t serialdbgtimer;
|
||||
void
|
||||
serial_dbg_timer(void *p)
|
||||
{
|
||||
double dbps = (double) 115200;
|
||||
double temp = 0.0;
|
||||
int word_len = 32;
|
||||
temp = (double) word_len;
|
||||
temp = (1000000.0 / dbps) * temp;
|
||||
if (serialdbg_reading) {
|
||||
if (HasOverlappedIoCompleted(&serialdbgoverlapped_r)) {
|
||||
if (!GetOverlappedResult(serialdbg, &serialdbgoverlapped_r, &serialdbg_read, FALSE)) {
|
||||
return;
|
||||
}
|
||||
//pclog("overlapped %d\n", serialdbg_read);
|
||||
for (uint32_t i = 0; i < serialdbg_read; i++) {
|
||||
pclog("reading %02X\n", serialdbg_buf[i]);
|
||||
serial_write_fifo((serial_t *) p, serialdbg_buf[i]);
|
||||
}
|
||||
serialdbg_reading = 0;
|
||||
}// else pclog(" not yet\n");
|
||||
} else {
|
||||
if (!ReadFile(serialdbg, serialdbg_buf, sizeof(serialdbg_buf), &serialdbg_read, &serialdbgoverlapped_r) && GetLastError() != ERROR_IO_PENDING) {
|
||||
pclog("serial broken (read) %08X\n", GetLastError());
|
||||
CancelIo(serialdbg);
|
||||
return;
|
||||
}
|
||||
serialdbg_reading = 1;
|
||||
}
|
||||
timer_on_auto(&serialdbgtimer, temp);//((serial_t *) p)->transmit_period);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
serial_write_fifo(serial_t *dev, uint8_t dat)
|
||||
{
|
||||
@@ -234,8 +193,6 @@ serial_write_fifo(serial_t *dev, uint8_t dat)
|
||||
|
||||
if (!(dev->mctrl & 0x10))
|
||||
write_fifo(dev, dat);
|
||||
else
|
||||
pclog("fifo not in rx mode?\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -246,14 +203,6 @@ serial_transmit(serial_t *dev, uint8_t val)
|
||||
write_fifo(dev, val);
|
||||
else if (dev->sd->dev_write)
|
||||
dev->sd->dev_write(dev, dev->sd->priv, val);
|
||||
if (serialdbg && dev->base_address == SERIAL1_ADDR) {
|
||||
uint8_t buf[1];
|
||||
buf[0] = val;
|
||||
pclog("writing %02X...", buf[0]);
|
||||
WriteFile(serialdbg, buf, 1, NULL, &serialdbgoverlapped_w);
|
||||
//while (!HasOverlappedIoCompleted(&serialdbgoverlapped_w));
|
||||
pclog("written\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -374,7 +323,6 @@ serial_update_speed(serial_t *dev)
|
||||
|
||||
if (timer_is_enabled(&dev->timeout_timer))
|
||||
timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period);
|
||||
//pclog("SPEED UPDATED!!! %f\n", dev->transmit_period);
|
||||
}
|
||||
|
||||
|
||||
@@ -756,15 +704,6 @@ serial_init(const device_t *info)
|
||||
|
||||
next_inst++;
|
||||
|
||||
if (dev->base_address == SERIAL1_ADDR) {
|
||||
serialdbg = CreateFileA(TEXT("\\\\.\\COM4"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
pclog("%02X\n", GetLastError());
|
||||
if (serialdbg)
|
||||
timer_add(&serialdbgtimer, serial_dbg_timer, dev, 1);
|
||||
else
|
||||
pclog("serial open failed??\n");
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@@ -10,10 +10,8 @@
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* RichardG, <richardg867@gmail.com>
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
@@ -27,57 +25,160 @@
|
||||
#include <86box/i2c.h>
|
||||
|
||||
|
||||
static uint8_t edid_data[128] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* Fixed header pattern */
|
||||
0x09, 0xf8, /* Manufacturer "BOX" - apparently unassigned by UEFI - and it has to be big endian */
|
||||
0x00, 0x00, /* Product code */
|
||||
0x12, 0x34, 0x56, 0x78, /* Serial number */
|
||||
47, 30, /* Manufacturer week and year */
|
||||
0x01, 0x03, /* EDID version (1.3) */
|
||||
#define STD_TIMING(idx, width, aspect_ratio) do { \
|
||||
edid.std_timings[idx].horiz_pixels = ((width) / 8) - 31; \
|
||||
edid.std_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \
|
||||
} while (0)
|
||||
|
||||
0x08, /* Analog input, separate sync */
|
||||
34, 0, /* Landscape, 4:3 */
|
||||
0, /* Gamma */
|
||||
0x08, /* RGB color */
|
||||
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */
|
||||
|
||||
0xff, 0xff, 0xff, /* Established timing bitmap */
|
||||
0x00, 0x00, /* Standard timing information */
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/* Detailed mode descriptions */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, /* No extensions */
|
||||
0x00
|
||||
enum {
|
||||
STD_ASPECT_16_10 = 0x0,
|
||||
STD_ASPECT_4_3,
|
||||
STD_ASPECT_5_4,
|
||||
STD_ASPECT_16_9
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t horiz_pixels, aspect_ratio_refresh_rate;
|
||||
} edid_std_timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pixel_clock_lsb, pixel_clock_msb, h_active_lsb, h_blank_lsb,
|
||||
h_active_blank_msb, v_active_lsb, v_blank_lsb, v_active_blank_msb,
|
||||
h_front_porch_lsb, h_sync_pulse_lsb, v_front_porch_sync_pulse_lsb,
|
||||
hv_front_porch_sync_pulse_msb, h_size_lsb, v_size_lsb, hv_size_msb,
|
||||
h_border, v_border, features;
|
||||
} edid_detailed_timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t min_v_field, max_v_field, min_h_line, max_h_line, max_pixel_clock,
|
||||
timing_type;
|
||||
union {
|
||||
uint8_t padding[7];
|
||||
struct {
|
||||
uint8_t reserved, gtf_start_freq, gtf_c, gtf_m_lsb, gtf_m_msb,
|
||||
gtf_k, gtf_j;
|
||||
};
|
||||
struct {
|
||||
uint8_t cvt_version, add_clock_precision, max_active_pixels,
|
||||
aspect_ratios, aspect_ratio_pref, scaling_support,
|
||||
refresh_pref;
|
||||
};
|
||||
};
|
||||
} edid_range_limits_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version, timings[6], reserved[6];
|
||||
} edid_established_timings3_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
struct {
|
||||
uint8_t lines_lsb, lines_msb_aspect_ratio, refresh_rate;
|
||||
} timings[4];
|
||||
} edid_cvt_timings_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t magic[2], reserved, type, range_limit_offsets;
|
||||
union {
|
||||
char ascii[13];
|
||||
edid_range_limits_t range_limits;
|
||||
edid_established_timings3_t established_timings3;
|
||||
edid_cvt_timings_t cvt_timings;
|
||||
};
|
||||
} edid_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t magic[8], mfg[2], mfg_product[2], serial[4], mfg_week, mfg_year,
|
||||
edid_version, edid_rev;
|
||||
uint8_t input_params, horiz_size, vert_size, gamma, features;
|
||||
uint8_t chromaticity[10], established_timings[3];
|
||||
edid_std_timing_t std_timings[8];
|
||||
union {
|
||||
edid_detailed_timing_t detailed_timings[4];
|
||||
edid_descriptor_t descriptors[4];
|
||||
};
|
||||
uint8_t extensions, checksum;
|
||||
} edid_t;
|
||||
|
||||
|
||||
static edid_t edid;
|
||||
|
||||
|
||||
void *
|
||||
ddc_init(void *i2c)
|
||||
{
|
||||
uint8_t checksum = 0;
|
||||
for (int c = 0; c < 127; c++)
|
||||
checksum += edid_data[c];
|
||||
edid_data[127] = 256 - checksum;
|
||||
memset(&edid.magic[1], 0xff, sizeof(edid.magic) - 2);
|
||||
edid.magic[0] = edid.magic[7] = 0x00;
|
||||
|
||||
return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid_data), 0);
|
||||
edid.mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */
|
||||
edid.mfg[1] = 0xf8;
|
||||
edid.mfg_week = 48;
|
||||
edid.mfg_year = 2020 - 1990;
|
||||
edid.edid_version = 0x01;
|
||||
edid.edid_rev = 0x03; /* EDID 1.3 */
|
||||
|
||||
edid.input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */
|
||||
edid.horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */
|
||||
edid.features = 0x09; /* RGB color; CVT */
|
||||
|
||||
edid.chromaticity[0] = 0x81;
|
||||
edid.chromaticity[1] = 0xf1;
|
||||
edid.chromaticity[2] = 0xa3;
|
||||
edid.chromaticity[3] = 0x57;
|
||||
edid.chromaticity[4] = 0x53;
|
||||
edid.chromaticity[5] = 0x9f;
|
||||
edid.chromaticity[6] = 0x27;
|
||||
edid.chromaticity[7] = 0x0a;
|
||||
edid.chromaticity[8] = 0x50;
|
||||
edid.chromaticity[9] = 0x00;
|
||||
|
||||
memset(&edid.established_timings, 0xff, sizeof(edid.established_timings)); /* all enabled */
|
||||
|
||||
memset(&edid.std_timings, 0x01, sizeof(edid.std_timings)); /* pad unused entries with 0x01 */
|
||||
STD_TIMING(0, 800, STD_ASPECT_4_3); /* 800x600 (preferred) */
|
||||
STD_TIMING(1, 1280, STD_ASPECT_16_9); /* 1280x720 */
|
||||
STD_TIMING(1, 1280, STD_ASPECT_16_10); /* 1280x800 */
|
||||
STD_TIMING(2, 1366, STD_ASPECT_16_9); /* 1360x768 (closest to 1366x768) */
|
||||
STD_TIMING(3, 1600, STD_ASPECT_16_9); /* 1600x900 */
|
||||
STD_TIMING(4, 1920, STD_ASPECT_16_9); /* 1920x1080 */
|
||||
STD_TIMING(5, 2048, STD_ASPECT_4_3); /* 2048x1536 */
|
||||
|
||||
/* Detailed timings for the preferred resolution of 800x600 */
|
||||
edid.detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */
|
||||
edid.detailed_timings[0].pixel_clock_msb = 0x0f;
|
||||
edid.detailed_timings[0].h_active_lsb = 800 & 0xff;
|
||||
edid.detailed_timings[0].h_blank_lsb = 256 & 0xff;
|
||||
edid.detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f);
|
||||
edid.detailed_timings[0].v_active_lsb = 600 & 0xff;
|
||||
edid.detailed_timings[0].v_blank_lsb = 28;
|
||||
edid.detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0;
|
||||
edid.detailed_timings[0].h_front_porch_lsb = 40;
|
||||
edid.detailed_timings[0].h_sync_pulse_lsb = 128;
|
||||
edid.detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4;
|
||||
|
||||
edid.descriptors[1].type = 0xf7; /* established timings 3 */
|
||||
edid.descriptors[1].established_timings3.version = 0x10;
|
||||
memset(&edid.descriptors[1].established_timings3.timings, 0xff, sizeof(edid.descriptors[1].established_timings3.timings)); /* all enabled */
|
||||
|
||||
edid.descriptors[2].type = 0xfc; /* display name */
|
||||
memcpy(&edid.descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */
|
||||
|
||||
edid.descriptors[3].type = 0xfd; /* range limits */
|
||||
edid.descriptors[3].range_limits.min_v_field = 1;
|
||||
edid.descriptors[3].range_limits.max_v_field = -1;
|
||||
edid.descriptors[3].range_limits.min_h_line = 1;
|
||||
edid.descriptors[3].range_limits.max_h_line = -1;
|
||||
edid.descriptors[3].range_limits.max_pixel_clock = -1;
|
||||
edid.descriptors[3].range_limits.timing_type = 0x00; /* default GTF */
|
||||
edid.descriptors[3].range_limits.padding[0] = 0x0a;
|
||||
memset(&edid.descriptors[3].range_limits.padding[1], 0x20, sizeof(edid.descriptors[3].range_limits.padding) - 1);
|
||||
|
||||
uint8_t *edid_data = (uint8_t *) &edid;
|
||||
for (uint8_t c = 0; c < 127; c++)
|
||||
edid.checksum += edid_data[c];
|
||||
edid.checksum = 256 - edid.checksum;
|
||||
|
||||
return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid), 0);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -118,7 +118,7 @@ typedef struct banshee_t
|
||||
|
||||
int type;
|
||||
|
||||
void *i2c, *ddc;
|
||||
void *i2c, *i2c_ddc, *ddc;
|
||||
} banshee_t;
|
||||
|
||||
enum
|
||||
@@ -685,7 +685,8 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
|
||||
case Video_vidSerialParallelPort:
|
||||
banshee->vidSerialParallelPort = val;
|
||||
// banshee_log("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc);
|
||||
i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W));
|
||||
i2c_gpio_set(banshee->i2c_ddc, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W));
|
||||
i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_I2C_SCK_W), !!(val & VIDSERIAL_I2C_SDA_W));
|
||||
break;
|
||||
|
||||
case Video_vidScreenSize:
|
||||
@@ -918,14 +919,14 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p)
|
||||
|
||||
case Video_vidSerialParallelPort:
|
||||
ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R);
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && i2c_gpio_get_scl(banshee->i2c))
|
||||
if (!(banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) || i2c_gpio_get_scl(banshee->i2c_ddc))
|
||||
ret |= VIDSERIAL_DDC_DCK_R;
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && i2c_gpio_get_sda(banshee->i2c))
|
||||
if (!(banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) || i2c_gpio_get_sda(banshee->i2c_ddc))
|
||||
ret |= VIDSERIAL_DDC_DDA_R;
|
||||
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
|
||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
|
||||
if (!(banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) || i2c_gpio_get_scl(banshee->i2c))
|
||||
ret |= VIDSERIAL_I2C_SCK_R;
|
||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W)
|
||||
if (!(banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W) || i2c_gpio_get_sda(banshee->i2c))
|
||||
ret |= VIDSERIAL_I2C_SDA_R;
|
||||
// banshee_log("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc);
|
||||
break;
|
||||
@@ -2628,8 +2629,9 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra
|
||||
|
||||
banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W;
|
||||
|
||||
banshee->i2c = i2c_gpio_init("ddc_voodoo_banshee");
|
||||
banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c));
|
||||
banshee->i2c = i2c_gpio_init("i2c_voodoo_banshee");
|
||||
banshee->i2c_ddc = i2c_gpio_init("ddc_voodoo_banshee");
|
||||
banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c_ddc));
|
||||
|
||||
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee);
|
||||
|
||||
@@ -2677,6 +2679,7 @@ static void banshee_close(void *p)
|
||||
voodoo_card_close(banshee->voodoo);
|
||||
svga_close(&banshee->svga);
|
||||
ddc_close(banshee->ddc);
|
||||
i2c_gpio_close(banshee->i2c_ddc);
|
||||
i2c_gpio_close(banshee->i2c);
|
||||
|
||||
free(banshee);
|
||||
|
Reference in New Issue
Block a user