DDC/I2C/SMBus overhaul (incomplete, commit for the night)
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include <86box/rom.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/vid_ddc.h>
|
||||
#include <86box/vid_svga.h>
|
||||
#include <86box/vid_svga_render.h>
|
||||
@@ -251,6 +252,8 @@ typedef struct mach64_t
|
||||
uint32_t buf_offset[2], buf_pitch[2];
|
||||
|
||||
int overlay_v_acc;
|
||||
|
||||
void *i2c;
|
||||
} mach64_t;
|
||||
|
||||
static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10};
|
||||
@@ -1740,7 +1743,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p)
|
||||
mach64_t *mach64 = (mach64_t *)p;
|
||||
uint8_t gpio_state;
|
||||
|
||||
uint8_t ret;
|
||||
uint8_t ret = 0xff;
|
||||
if (!(addr & 0x400))
|
||||
{
|
||||
mach64_log("nmach64_ext_readb: addr=%04x\n", addr);
|
||||
@@ -1879,11 +1882,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p)
|
||||
|
||||
if ((ret & (1 << 4)) && !(ret & (1 << 1)))
|
||||
gpio_state &= ~(1 << 1);
|
||||
if (!(ret & (1 << 4)) && !ddc_read_data())
|
||||
if (!(ret & (1 << 4)) && !i2c_gpio_get_sda(mach64->i2c))
|
||||
gpio_state &= ~(1 << 1);
|
||||
if ((ret & (1 << 5)) && !(ret & (1 << 2)))
|
||||
gpio_state &= ~(1 << 2);
|
||||
if (!(ret & (1 << 5)) && !ddc_read_clock())
|
||||
if (!(ret & (1 << 5)) && !i2c_gpio_get_scl(mach64->i2c))
|
||||
gpio_state &= ~(1 << 2);
|
||||
|
||||
ret = (ret & ~6) | gpio_state;
|
||||
@@ -2381,7 +2384,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p)
|
||||
ati68860_set_ramdac_type(mach64->svga.ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT);
|
||||
data = (val & (1 << 4)) ? ((val & (1 << 1)) ? 1 : 0) : 1;
|
||||
clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 1 : 0) : 1;
|
||||
ddc_i2c_change(clk, data);
|
||||
i2c_gpio_set(mach64->i2c, clk, data);
|
||||
break;
|
||||
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
||||
@@ -3368,7 +3371,8 @@ static void *mach64_common_init(const device_t *info)
|
||||
mach64->fifo_not_full_event = thread_create_event();
|
||||
mach64->fifo_thread = thread_create(fifo_thread, mach64);
|
||||
|
||||
ddc_init();
|
||||
mach64->i2c = i2c_gpio_init("ddc_ati_mach64");
|
||||
ddc_init(i2c_gpio_get_bus(mach64->i2c));
|
||||
|
||||
return mach64;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
@@ -14,321 +11,122 @@
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2020 RichardG.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/vid_ddc.h>
|
||||
#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*/
|
||||
0x01, 9, /*Manufacturer week and year*/
|
||||
0x01, 0x03, /*EDID version (1.3)*/
|
||||
typedef struct {
|
||||
uint8_t addr_register;
|
||||
} ddc_t;
|
||||
|
||||
0x08, /*Analogue input, separate sync*/
|
||||
34, 0, /*Landscape, 4:3*/
|
||||
0, /*Gamma*/
|
||||
0x08, /*RGB colour*/
|
||||
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,
|
||||
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) */
|
||||
|
||||
/*Detailed mode descriptions*/
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, /* Analog input, separate sync */
|
||||
34, 0, /* Landscape, 4:3 */
|
||||
0, /* Gamma */
|
||||
0x08, /* RGB colour */
|
||||
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
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,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 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, /*No extensions*/
|
||||
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
|
||||
};
|
||||
|
||||
/*This should probably be split off into a separate I2C module*/
|
||||
enum
|
||||
{
|
||||
TRANSMITTER_MONITOR = 1,
|
||||
TRANSMITTER_HOST = -1
|
||||
};
|
||||
|
||||
enum
|
||||
uint8_t
|
||||
ddc_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
I2C_IDLE = 0,
|
||||
I2C_RECEIVE,
|
||||
I2C_RECEIVE_WAIT,
|
||||
I2C_TRANSMIT_START,
|
||||
I2C_TRANSMIT,
|
||||
I2C_ACKNOWLEDGE,
|
||||
I2C_TRANSACKNOWLEDGE,
|
||||
I2C_TRANSMIT_WAIT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROM_IDLE = 0,
|
||||
PROM_RECEIVEADDR,
|
||||
PROM_RECEIVEDATA,
|
||||
PROM_SENDDATA,
|
||||
PROM_INVALID
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int clock, data;
|
||||
int state;
|
||||
int last_data;
|
||||
int pos;
|
||||
int transmit;
|
||||
uint8_t byte;
|
||||
} i2c;
|
||||
|
||||
static struct
|
||||
{
|
||||
int state;
|
||||
int addr;
|
||||
int rw;
|
||||
} prom;
|
||||
|
||||
static void prom_stop(void)
|
||||
{
|
||||
// pclog("prom_stop()\n");
|
||||
prom.state = PROM_IDLE;
|
||||
i2c.transmit = TRANSMITTER_HOST;
|
||||
return edid_data[cmd & 0x7f];
|
||||
}
|
||||
|
||||
static void prom_next_byte(void)
|
||||
|
||||
uint8_t
|
||||
ddc_read_byte(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
// pclog("prom_next_byte(%d)\n", prom.addr);
|
||||
i2c.byte = edid_data[(prom.addr++) & 0x7F];
|
||||
ddc_t *dev = (ddc_t *) priv;
|
||||
return ddc_read_byte_cmd(bus, addr, dev->addr_register++, priv);
|
||||
}
|
||||
|
||||
static void prom_write(uint8_t byte)
|
||||
|
||||
uint16_t
|
||||
ddc_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
// pclog("prom_write: byte=%02x\n", byte);
|
||||
switch (prom.state)
|
||||
{
|
||||
case PROM_IDLE:
|
||||
if ((byte & 0xfe) != 0xa0)
|
||||
{
|
||||
// pclog("I2C address not PROM\n");
|
||||
prom.state = PROM_INVALID;
|
||||
break;
|
||||
}
|
||||
prom.rw = byte & 1;
|
||||
if (prom.rw)
|
||||
{
|
||||
prom.state = PROM_SENDDATA;
|
||||
i2c.transmit = TRANSMITTER_MONITOR;
|
||||
i2c.byte = edid_data[(prom.addr++) & 0x7F];
|
||||
// pclog("PROM - %02X from %02X\n",i2c.byte, prom.addr-1);
|
||||
// pclog("Transmitter now PROM\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
prom.state = PROM_RECEIVEADDR;
|
||||
i2c.transmit = TRANSMITTER_HOST;
|
||||
}
|
||||
// pclog("PROM R/W=%i\n",promrw);
|
||||
return;
|
||||
|
||||
case PROM_RECEIVEADDR:
|
||||
// pclog("PROM addr=%02X\n",byte);
|
||||
prom.addr = byte;
|
||||
if (prom.rw)
|
||||
prom.state = PROM_SENDDATA;
|
||||
else
|
||||
prom.state = PROM_RECEIVEDATA;
|
||||
break;
|
||||
|
||||
case PROM_RECEIVEDATA:
|
||||
// pclog("PROM write %02X %02X\n",promaddr,byte);
|
||||
break;
|
||||
|
||||
case PROM_SENDDATA:
|
||||
break;
|
||||
}
|
||||
return (ddc_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | ddc_read_byte_cmd(bus, addr, cmd, priv);
|
||||
}
|
||||
|
||||
void ddc_i2c_change(int new_clock, int new_data)
|
||||
|
||||
uint8_t
|
||||
ddc_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv)
|
||||
{
|
||||
// pclog("I2C update clock %i->%i data %i->%i state %i\n",i2c.clock,new_clock,i2c.last_data,new_data,i2c.state);
|
||||
switch (i2c.state)
|
||||
{
|
||||
case I2C_IDLE:
|
||||
if (i2c.clock && new_clock)
|
||||
{
|
||||
if (i2c.last_data && !new_data) /*Start bit*/
|
||||
{
|
||||
// pclog("Start bit received\n");
|
||||
i2c.state = I2C_RECEIVE;
|
||||
i2c.pos = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_RECEIVE_WAIT:
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.state = I2C_RECEIVE;
|
||||
case I2C_RECEIVE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
i2c.byte <<= 1;
|
||||
if (new_data)
|
||||
i2c.byte |= 1;
|
||||
else
|
||||
i2c.byte &= 0xFE;
|
||||
i2c.pos++;
|
||||
if (i2c.pos == 8)
|
||||
{
|
||||
prom_write(i2c.byte);
|
||||
i2c.state = I2C_ACKNOWLEDGE;
|
||||
}
|
||||
}
|
||||
else if (i2c.clock && new_clock && new_data && !i2c.last_data) /*Stop bit*/
|
||||
{
|
||||
// pclog("Stop bit received\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
else if (i2c.clock && new_clock && !new_data && i2c.last_data) /*Start bit*/
|
||||
{
|
||||
// pclog("Start bit received\n");
|
||||
i2c.pos = 0;
|
||||
prom.state = PROM_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_ACKNOWLEDGE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
// pclog("Acknowledging transfer\n");
|
||||
new_data = 0;
|
||||
i2c.pos = 0;
|
||||
if (i2c.transmit == TRANSMITTER_HOST)
|
||||
i2c.state = I2C_RECEIVE_WAIT;
|
||||
else
|
||||
i2c.state = I2C_TRANSMIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSACKNOWLEDGE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
if (new_data) /*It's not acknowledged - must be end of transfer*/
|
||||
{
|
||||
// pclog("End of transfer\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
else /*Next byte to transfer*/
|
||||
{
|
||||
i2c.state = I2C_TRANSMIT_START;
|
||||
prom_next_byte();
|
||||
i2c.pos = 0;
|
||||
// pclog("Next byte - %02X\n",i2c.byte);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSMIT_WAIT:
|
||||
if (i2c.clock && new_clock)
|
||||
{
|
||||
if (i2c.last_data && !new_data) /*Start bit*/
|
||||
{
|
||||
prom_next_byte();
|
||||
i2c.pos = 0;
|
||||
// pclog("Next byte - %02X\n",i2c.byte);
|
||||
}
|
||||
if (!i2c.last_data && new_data) /*Stop bit*/
|
||||
{
|
||||
// pclog("Stop bit received\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSMIT_START:
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.state = I2C_TRANSMIT;
|
||||
if (i2c.clock && new_clock && !i2c.last_data && new_data) /*Stop bit*/
|
||||
{
|
||||
// pclog("Stop bit received\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
case I2C_TRANSMIT:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
i2c.clock = new_clock;
|
||||
// if (!i2c.pos)
|
||||
// pclog("Transmit byte %02x\n", i2c.byte);
|
||||
i2c.data = new_data = i2c.byte & 0x80;
|
||||
// pclog("Transmit bit %i %i\n", i2c.byte, i2c.pos);
|
||||
i2c.byte <<= 1;
|
||||
i2c.pos++;
|
||||
return;
|
||||
}
|
||||
if (i2c.clock && !new_clock && i2c.pos == 8)
|
||||
{
|
||||
i2c.state = I2C_TRANSACKNOWLEDGE;
|
||||
// pclog("Acknowledge mode\n");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.data = new_data;
|
||||
i2c.last_data = new_data;
|
||||
i2c.clock = new_clock;
|
||||
uint8_t read = 0;
|
||||
for (uint8_t i = cmd; (i < len) && (i < 0x80); i++)
|
||||
data[read++] = ddc_read_byte_cmd(bus, addr, i, priv);
|
||||
return read;
|
||||
}
|
||||
|
||||
int ddc_read_clock(void)
|
||||
|
||||
void
|
||||
ddc_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
return i2c.clock;
|
||||
}
|
||||
int ddc_read_data(void)
|
||||
{
|
||||
if (i2c.state == I2C_TRANSMIT || i2c.state == I2C_ACKNOWLEDGE)
|
||||
return i2c.data;
|
||||
if (i2c.state == I2C_RECEIVE_WAIT)
|
||||
return 0; /*ACK*/
|
||||
return 1;
|
||||
ddc_t *dev = (ddc_t *) priv;
|
||||
dev->addr_register = val;
|
||||
}
|
||||
|
||||
void ddc_init(void)
|
||||
|
||||
void
|
||||
ddc_init(void *i2c)
|
||||
{
|
||||
int c;
|
||||
uint8_t checksum = 0;
|
||||
ddc_t *dev = (ddc_t *) malloc(sizeof(ddc_t));
|
||||
memset(dev, 0, sizeof(ddc_t));
|
||||
|
||||
for (c = 0; c < 127; c++)
|
||||
checksum += edid_data[c];
|
||||
edid_data[127] = 256 - checksum;
|
||||
uint8_t checksum = 0;
|
||||
for (int c = 0; c < 127; c++)
|
||||
checksum += edid_data[c];
|
||||
edid_data[127] = 256 - checksum;
|
||||
|
||||
i2c.clock = 1;
|
||||
i2c.data = 1;
|
||||
i2c_sethandler(i2c, 0x50, 1,
|
||||
NULL, ddc_read_byte, ddc_read_byte_cmd, ddc_read_word_cmd, ddc_read_block_cmd,
|
||||
NULL, ddc_write_byte, NULL, NULL, NULL,
|
||||
dev);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <86box/device.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/vid_ddc.h>
|
||||
#include <86box/vid_svga.h>
|
||||
#include <86box/vid_svga_render.h>
|
||||
@@ -286,6 +287,8 @@ typedef struct virge_t
|
||||
uint8_t subsys_stat, subsys_cntl, advfunc_cntl;
|
||||
|
||||
uint8_t serialport;
|
||||
|
||||
void *i2c;
|
||||
} virge_t;
|
||||
|
||||
static video_timings_t timing_diamond_stealth3d_2000_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45};
|
||||
@@ -894,9 +897,9 @@ s3_virge_mmio_read(uint32_t addr, void *p)
|
||||
|
||||
case 0xff20: case 0xff21:
|
||||
ret = virge->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR);
|
||||
if ((virge->serialport & SERIAL_PORT_SCW) && ddc_read_clock())
|
||||
if ((virge->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c))
|
||||
ret |= SERIAL_PORT_SCR;
|
||||
if ((virge->serialport & SERIAL_PORT_SDW) && ddc_read_data())
|
||||
if ((virge->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c))
|
||||
ret |= SERIAL_PORT_SDR;
|
||||
return ret;
|
||||
}
|
||||
@@ -1180,7 +1183,7 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
|
||||
|
||||
case 0xff20:
|
||||
virge->serialport = val;
|
||||
ddc_i2c_change((val & SERIAL_PORT_SCW) ? 1 : 0, (val & SERIAL_PORT_SDW) ? 1 : 0);
|
||||
i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3845,7 +3848,8 @@ static void *s3_virge_init(const device_t *info)
|
||||
virge->fifo_not_full_event = thread_create_event();
|
||||
virge->fifo_thread = thread_create(fifo_thread, virge);
|
||||
|
||||
ddc_init();
|
||||
virge->i2c = i2c_gpio_init("ddc_s3_virge");
|
||||
ddc_init(i2c_gpio_get_bus(virge->i2c));
|
||||
|
||||
return virge;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <86box/device.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/vid_ddc.h>
|
||||
#include <86box/vid_svga.h>
|
||||
#include <86box/vid_svga_render.h>
|
||||
@@ -116,6 +117,8 @@ typedef struct banshee_t
|
||||
uint32_t desktop_stride_tiled;
|
||||
|
||||
int type;
|
||||
|
||||
void *i2c;
|
||||
} banshee_t;
|
||||
|
||||
enum
|
||||
@@ -682,7 +685,7 @@ 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);
|
||||
ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0);
|
||||
i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W));
|
||||
break;
|
||||
|
||||
case Video_vidScreenSize:
|
||||
@@ -915,9 +918,9 @@ 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) && ddc_read_clock())
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && i2c_gpio_get_scl(banshee->i2c))
|
||||
ret |= VIDSERIAL_DDC_DCK_R;
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && ddc_read_data())
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && i2c_gpio_get_sda(banshee->i2c))
|
||||
ret |= VIDSERIAL_DDC_DDA_R;
|
||||
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
|
||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
|
||||
@@ -2625,7 +2628,8 @@ 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;
|
||||
|
||||
ddc_init();
|
||||
banshee->i2c = i2c_gpio_init("ddc_voodoo_banshee");
|
||||
ddc_init(i2c_gpio_get_bus(banshee->i2c));
|
||||
|
||||
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee);
|
||||
|
||||
@@ -2672,6 +2676,7 @@ static void banshee_close(void *p)
|
||||
|
||||
voodoo_card_close(banshee->voodoo);
|
||||
svga_close(&banshee->svga);
|
||||
i2c_gpio_close(banshee->i2c);
|
||||
|
||||
free(banshee);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user