diff --git a/src/devices/machine/k056230.cpp b/src/devices/machine/k056230.cpp
index 487a26da35daa..8aa0ab182f393 100644
--- a/src/devices/machine/k056230.cpp
+++ b/src/devices/machine/k056230.cpp
@@ -1,8 +1,8 @@
 // license:BSD-3-Clause
-// copyright-holders:Fabio Priuli
+// copyright-holders:Fabio Priuli, Ariane Fugmann
 /**************************************************************************************************
 
-Konami IC 056230 (LANC)
+Konami IC 056230 (LANC) / KS40011
 
 Device Notes:
 -The custom IC itself
@@ -13,15 +13,20 @@ Device Notes:
 -HYC2485S RS485 transceiver
 
 TODO:
-- nearly everything, currently a wrapper to make games happy and don't fail POSTs
+- "manual" TX/RX mode
 - LANC part name for konami/viper.cpp
 
 **************************************************************************************************/
 
 #include "emu.h"
-
 #include "k056230.h"
 
+#include "emuopts.h"
+
+#include "asio.h"
+
+#include <iostream>
+
 #define LOG_REG_READS   (1U << 1)
 #define LOG_REG_WRITES  (1U << 2)
 #define LOG_RAM_READS   (1U << 3)
@@ -32,13 +37,469 @@ Device Notes:
 #define VERBOSE (0)
 #include "logmacro.h"
 
+class k056230_device::context
+{
+public:
+	context(k056230_device &device) :
+		m_device(device),
+		m_acceptor(m_ioctx),
+		m_sock_rx(m_ioctx),
+		m_sock_tx(m_ioctx),
+		m_timeout_tx(m_ioctx),
+		m_stopping(false),
+		m_state_rx(0U),
+		m_state_tx(0U)
+	{
+	}
+
+	void start()
+	{
+
+		m_thread = std::thread(
+				[this] ()
+				{
+					LOG("network thread started\n");
+					try {
+						m_ioctx.run();
+					} catch (const std::exception& e) {
+						LOG("Exception in network thread: %s\n", e.what());
+					} catch (...) { // Catch any other unknown exceptions
+						LOG("Unknown exception in network thread\n");
+					}
+					LOG("network thread completed\n");
+				});
+	}
+
+	void reset(std::string localhost, std::string localport, std::string remotehost, std::string remoteport)
+	{
+		m_ioctx.post(
+				[this, localhost = std::move(localhost), localport = std::move(localport), remotehost = std::move(remotehost), remoteport = std::move(remoteport)] ()
+				{
+					std::error_code err;
+					asio::ip::tcp::resolver resolver(m_ioctx);
+
+					for (auto &&resolveIte : resolver.resolve(localhost, localport, asio::ip::tcp::resolver::flags::address_configured, err))
+					{
+						m_localaddr = resolveIte.endpoint();
+						LOG("localhost = %s\n", *m_localaddr);
+					}
+					if (err)
+					{
+						LOG("localhost resolve error: %s\n", err.message());
+					}
+
+					for (auto &&resolveIte : resolver.resolve(remotehost, remoteport, asio::ip::tcp::resolver::flags::address_configured, err))
+					{
+						m_remoteaddr = resolveIte.endpoint();
+						LOG("remotehost = %s\n", *m_remoteaddr);
+					}
+					if (err)
+					{
+						LOG("remotehost resolve error: %s\n", err.message());
+					}
+
+					if (m_acceptor.is_open())
+						m_acceptor.close(err);
+					if (m_sock_rx.is_open())
+						m_sock_rx.close(err);
+					if (m_sock_tx.is_open())
+						m_sock_tx.close(err);
+					m_timeout_tx.cancel();
+					m_state_rx.store(0);
+					m_state_tx.store(0);
+					start_accept();
+					start_connect();
+				});
+	}
+
+	void stop()
+	{
+		m_ioctx.post(
+				[this] ()
+				{
+					m_stopping = true;
+					std::error_code err;
+					if (m_acceptor.is_open())
+						m_acceptor.close(err);
+					if (m_sock_rx.is_open())
+						m_sock_rx.close(err);
+					if (m_sock_tx.is_open())
+						m_sock_tx.close(err);
+					m_timeout_tx.cancel();
+					m_state_rx.store(0);
+					m_state_tx.store(0);
+					m_ioctx.stop();
+				});
+		m_work_guard.reset();
+		if (m_thread.joinable()) {
+			m_thread.join();
+		}
+	}
+
+	void check_sockets()
+	{
+	}
+
+	bool connected()
+	{
+		return m_state_rx.load() == 2 && m_state_tx.load() == 2;
+	}
+
+	unsigned receive(uint8_t *buffer, unsigned data_size)
+	{
+		if (m_state_rx.load() < 2)
+			return UINT_MAX;
+
+		if (data_size > m_fifo_rx.used())
+			return 0;
+
+		return m_fifo_rx.read(&buffer[0], data_size, false);
+	}
+
+	unsigned send(uint8_t *buffer, unsigned data_size)
+	{
+		if (m_state_tx.load() < 2)
+			return UINT_MAX;
+
+		if (data_size > m_fifo_tx.free())
+		{
+			LOG("TX buffer overflow\n");
+			return UINT_MAX;
+		}
+
+		bool const sending = m_fifo_tx.used();
+		m_fifo_tx.write(&buffer[0], data_size);
+		if (!sending)
+			m_ioctx.post(
+					[this] ()
+					{
+						start_send_tx();
+					});
+		return data_size;
+	}
+
+private:
+	class fifo
+	{
+	public:
+		fifo() :
+			m_wp(0),
+			m_rp(0)
+		{
+		}
+
+		unsigned write(uint8_t* buffer, unsigned data_size)
+		{
+			unsigned current_rp = m_rp.load(std::memory_order_acquire);
+			unsigned current_wp = m_wp.load(std::memory_order_relaxed);
+
+			// calculate free space
+			unsigned data_free = (BUFFER_SIZE + current_rp - current_wp - 1) % BUFFER_SIZE;
+
+			// sanity checks
+			if (data_size > data_free)
+				return UINT_MAX;
+			if (data_size == 0)
+				return 0;
+
+			unsigned data_used = 0;
+
+			// first part (up to end)
+			unsigned block = std::min(data_size, BUFFER_SIZE - current_wp);
+			std::copy_n(&buffer[0], block, &m_buffer[current_wp]);
+			data_used += block;
+			current_wp = (current_wp + block) % BUFFER_SIZE;
+
+			// second part (from beginning, if wrapped)
+			if (data_used < data_size)
+			{
+				block = data_size - data_used;
+				std::copy_n(&buffer[data_used], block, &m_buffer[current_wp]);
+				data_used += block;
+				current_wp += block;
+			}
+
+			m_wp.store(current_wp, std::memory_order_release);
+			return data_used;
+		}
+
+		unsigned read(uint8_t* buffer, unsigned data_size, bool peek)
+		{
+			unsigned current_wp = m_wp.load(std::memory_order_acquire);
+			unsigned current_rp = m_rp.load(std::memory_order_relaxed);
+
+			// calculate available data
+			unsigned data_avail = (BUFFER_SIZE + current_wp - current_rp) % BUFFER_SIZE;
+
+			// sanity checks
+			if (data_size > data_avail)
+				return UINT_MAX;
+			if (data_size == 0)
+				return 0;
+
+			unsigned data_used = 0;
+
+			// first part (up to end)
+			unsigned block = std::min(data_size, BUFFER_SIZE - current_rp);
+			std::copy_n(&m_buffer[current_rp], block, &buffer[0]);
+			data_used += block;
+			current_rp = (current_rp + data_used) % BUFFER_SIZE;
+
+			// second part (from beginning, if wrapped)
+			if (data_used < data_size)
+			{
+				block = data_size - data_used;
+				std::copy_n(&m_buffer[current_rp], block, &buffer[data_used]);
+				data_used += block;
+				current_rp += block;
+			}
+			if (!peek)
+			{
+				m_rp.store(current_rp, std::memory_order_release);
+			}
+			return data_used;
+		}
+
+		void consume(unsigned data_size)
+		{
+			unsigned current_wp = m_wp.load(std::memory_order_acquire);
+			unsigned current_rp = m_rp.load(std::memory_order_relaxed);
+
+			//  available data
+			unsigned data_avail = (BUFFER_SIZE + current_wp - current_rp) % BUFFER_SIZE;
+
+			// sanity check
+			if (data_size > data_avail)
+				data_size = data_avail;
+
+			current_rp = (current_rp + data_size) % BUFFER_SIZE;
+			m_rp.store(current_rp, std::memory_order_release);
+		}
+
+		unsigned used()
+		{
+			unsigned current_wp = m_wp.load(std::memory_order_acquire);
+			unsigned current_rp = m_rp.load(std::memory_order_acquire);
+			return (BUFFER_SIZE + current_wp - current_rp) % BUFFER_SIZE;
+		}
+
+		unsigned free()
+		{
+			unsigned current_wp = m_wp.load(std::memory_order_acquire);
+			unsigned current_rp = m_rp.load(std::memory_order_acquire);
+			return (BUFFER_SIZE + current_rp - current_wp - 1 + BUFFER_SIZE) % BUFFER_SIZE;
+		}
+
+		void clear()
+		{
+			m_wp.store(0, std::memory_order_release);
+			m_rp.store(0, std::memory_order_release);
+		}
+
+	private:
+		static constexpr unsigned BUFFER_SIZE = 0x80000;
+		std::atomic<unsigned> m_wp;
+		std::atomic<unsigned> m_rp;
+		std::array<uint8_t, BUFFER_SIZE> m_buffer;
+	};
+
+	void start_accept()
+	{
+		if (m_stopping)
+			return;
+
+		std::error_code err;
+		m_acceptor.open(m_localaddr->protocol(), err);
+		m_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
+		if (!err)
+		{
+			m_acceptor.bind(*m_localaddr, err);
+			if (!err)
+			{
+				m_acceptor.listen(1, err);
+				if (!err)
+				{
+					osd_printf_verbose("k056230: RX listen on %s\n", *m_localaddr);
+					m_acceptor.async_accept(
+							[this] (std::error_code const &err, asio::ip::tcp::socket sock)
+							{
+								if (err)
+								{
+									LOG("RX error accepting - %d %s\n", err.value(), err.message());
+									std::error_code e;
+									m_acceptor.close(e);
+									m_state_rx.store(0);
+									start_accept();
+								}
+								else
+								{
+									LOG("RX connection from %s\n", sock.remote_endpoint());
+									std::error_code e;
+									m_acceptor.close(e);
+									m_sock_rx = std::move(sock);
+									m_sock_rx.set_option(asio::socket_base::keep_alive(true));
+									m_state_rx.store(2);
+									start_receive_rx();
+								}
+							});
+					m_state_rx.store(1);
+				}
+			}
+		}
+		if (err)
+		{
+			LOG("RX failed - %d %s\n", err.value(), err.message());
+		}
+	}
+
+	void start_connect()
+	{
+		if (m_stopping)
+			return;
+
+		std::error_code err;
+		if (m_sock_tx.is_open())
+			m_sock_tx.close(err);
+		m_sock_tx.open(m_remoteaddr->protocol(), err);
+		if (!err)
+		{
+			m_sock_tx.set_option(asio::ip::tcp::no_delay(true));
+			m_sock_tx.set_option(asio::socket_base::keep_alive(true));
+			osd_printf_verbose("k056230: TX connecting to %s\n", *m_remoteaddr);
+			m_timeout_tx.expires_after(std::chrono::seconds(10));
+			m_timeout_tx.async_wait(
+					[this] (std::error_code const &err)
+					{
+						if (!err && m_state_tx.load() == 1)
+						{
+							osd_printf_verbose("k056230: TX connect timed out\n");
+							std::error_code e;
+							m_sock_tx.close(e);
+							m_state_tx.store(0);
+							start_connect();
+						}
+					});
+			m_sock_tx.async_connect(
+					*m_remoteaddr,
+					[this] (std::error_code const &err)
+					{
+						m_timeout_tx.cancel();
+						if (err)
+						{
+							osd_printf_verbose("k056230: TX connect error - %d %s\n", err.value(), err.message());
+							std::error_code e;
+							m_sock_tx.close(e);
+							m_state_tx.store(0);
+							start_connect();
+						}
+						else
+						{
+							LOG("TX connection established\n");
+							m_state_tx.store(2);
+						}
+					});
+			m_state_tx.store(1);
+		}
+	}
+
+	void start_send_tx()
+	{
+		if (m_stopping)
+			return;
+
+		unsigned used = m_fifo_tx.read(&m_buffer_tx[0], std::min<unsigned>(m_fifo_tx.used(), m_buffer_tx.size()), true);
+		m_sock_tx.async_write_some(
+				asio::buffer(&m_buffer_tx[0], used),
+				[this] (std::error_code const &err, std::size_t length)
+				{
+					m_fifo_tx.consume(length);
+					if (err)
+					{
+						LOG("TX connection error: %s\n", err.message().c_str());
+						m_sock_tx.close();
+						m_state_tx.store(0);
+						m_fifo_tx.clear();
+						start_connect();
+					}
+					else if (m_fifo_tx.used())
+					{
+						start_send_tx();
+					}
+				});
+	}
+
+	void start_receive_rx()
+	{
+		if (m_stopping)
+			return;
+
+		m_sock_rx.async_read_some(
+				asio::buffer(m_buffer_rx),
+				[this] (std::error_code const &err, std::size_t length)
+				{
+					if (err || !length)
+					{
+						if (err)
+							LOG("RX connection error: %s\n", err.message());
+						else
+							LOG("RX connection lost\n");
+						m_sock_rx.close();
+						m_state_rx.store(0);
+						m_fifo_rx.clear();
+						start_accept();
+					}
+					else
+					{
+						if (UINT_MAX == m_fifo_rx.write(&m_buffer_rx[0], length))
+						{
+							LOG("RX buffer overflow\n");
+							m_sock_rx.close();
+							m_state_rx.store(0);
+							m_fifo_rx.clear();
+							start_accept();
+							return;
+						}
+						start_receive_rx();
+					}
+				});
+	}
+
+	template <typename Format, typename... Params>
+	void logerror(Format &&fmt, Params &&... args) const
+	{
+		util::stream_format(
+				std::cerr,
+				"[%s] %s",
+				m_device.tag(),
+				util::string_format(std::forward<Format>(fmt), std::forward<Params>(args)...));
+	}
+
+	k056230_device &m_device;
+	std::thread m_thread;
+	asio::io_context m_ioctx;
+	asio::executor_work_guard<asio::io_context::executor_type> m_work_guard{m_ioctx.get_executor()};
+	std::optional<asio::ip::tcp::endpoint> m_localaddr;
+	std::optional<asio::ip::tcp::endpoint> m_remoteaddr;
+	asio::ip::tcp::acceptor m_acceptor;
+	asio::ip::tcp::socket m_sock_rx;
+	asio::ip::tcp::socket m_sock_tx;
+	asio::steady_timer m_timeout_tx;
+	bool m_stopping;
+	std::atomic_uint m_state_rx;
+	std::atomic_uint m_state_tx;
+	fifo m_fifo_rx;
+	fifo m_fifo_tx;
+	std::array<uint8_t, 0x400> m_buffer_rx;
+	std::array<uint8_t, 0x400> m_buffer_tx;
+};
+
 DEFINE_DEVICE_TYPE(K056230, k056230_device, "k056230", "K056230 LANC")
 DEFINE_DEVICE_TYPE(K056230_VIPER, k056230_viper_device, "k056230_viper", "Konami Viper LANC")
 
 k056230_device::k056230_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
-	: device_t(mconfig, type, tag, owner, clock)
-	, m_ram(*this, "lanc_ram", 0x800U * 4, ENDIANNESS_BIG)
-	, m_irq_cb(*this)
+	: device_t(mconfig, type, tag, owner, clock),
+	m_ram(*this, "lanc_ram", 0x2000U, ENDIANNESS_BIG),
+	m_irq_cb(*this)
 {
 }
 
@@ -49,76 +510,320 @@ k056230_device::k056230_device(const machine_config &mconfig, const char *tag, d
 
 void k056230_device::device_start()
 {
+	m_tick_timer = timer_alloc(FUNC(k056230_device::tick_timer_callback), this);
+	m_tick_timer->adjust(attotime::never);
+
+	auto ctx = std::make_unique<context>(*this);
+	m_context = std::move(ctx);
+	m_context->start();
+
+	// state saving
+	save_item(NAME(m_irq_enable));
 	save_item(NAME(m_irq_state));
 	save_item(NAME(m_status));
+
+	save_item(NAME(m_linkenable));
+	save_item(NAME(m_linkmaster));
+	save_item(NAME(m_linkid));
+	save_item(NAME(m_linkidm));
+	save_item(NAME(m_linksize));
+	save_item(NAME(m_txmode));
 }
 
 void k056230_device::device_reset()
 {
+	m_irq_enable = false;
 	m_irq_state = CLEAR_LINE;
-	m_status = 0x08;
+	m_status = 0;
+
+	std::fill(std::begin(m_buffer), std::end(m_buffer), 0);
+
+	auto const &opts = mconfig().options();
+	m_context->reset(opts.comm_localhost(), opts.comm_localport(), opts.comm_remotehost(), opts.comm_remoteport());
+
+	m_linkenable = false;
+	m_linkmaster = false;
+	m_linkid = 0;
+	m_linkidm = 0;
+	m_linksize = 0;
+	m_txmode = 0;
+
+	m_tick_timer->adjust(attotime::from_hz(800), 0, attotime::from_hz(800));
+}
+
+
+void k056230_device::device_stop()
+{
+	m_tick_timer->adjust(attotime::never);
+
+	m_context->stop();
+	m_context.reset();
 }
 
 void k056230_device::regs_map(address_map &map)
 {
 	map(0x00, 0x00).lrw8(
 		NAME([this] (offs_t offset) {
-			LOGMASKED(LOG_REG_READS, "%s: Status Register read %02x\n", machine().describe_context(), m_status);
-			return m_status;
+			/*
+			status register bits:
+			    2,1,0 = TID, transmit status
+			    3     = RXD
+			    4     = INTST-, 0 when INT
+			    5     = RUNST, 1 when comms active
+			    7,6   = unused
+			*/
+			u8 data = 0x08 | m_status;
+			if (!machine().side_effects_disabled())
+				LOGMASKED(LOG_REG_READS, "%s: Status Register read %02x\n", machine().describe_context(), data);
+			return data;
 		}),
 		NAME([this] (offs_t offset, u8 data) {
-			LOGMASKED(LOG_REG_WRITES, "%s: Mode Register read %02x\n", machine().describe_context(), data);
+			/*
+			mode register bits:
+			    2,1,0 = ID  - 0 to 7
+			    4,3   = IDM - 0, 1, 3 valid, 2 invalid
+			    5     = M/S - 1 means MASTER
+			    6     = TXD
+			    7     = TXM - 1 means TX line will be whatever TXD is set to. (not implemented)
+			*/
+			LOGMASKED(LOG_REG_WRITES, "%s: Mode Register write %02x\n", machine().describe_context(), data);
+			set_mode(data);
 		})
 	),
 	map(0x01, 0x01).lrw8(
 		NAME([this] (offs_t offset) {
+			/*
+			crc error register bits:
+			    each bit signals a receive error from the corrosponding main-id (bit 0 = id 0 etc.)
+			*/
 			const u8 res = 0x00;
-			LOGMASKED(LOG_REG_READS, "%s: CRC Error Register read %02x\n", machine().describe_context(), res);
+			if (!machine().side_effects_disabled())
+				LOGMASKED(LOG_REG_READS, "%s: CRC Error Register read %02x\n", machine().describe_context(), res);
 			return res;
 		}),
 		NAME([this] (offs_t offset, u8 data) {
+			/*
+			control register bits:
+			    0   = START
+			    1   = INTPR - 1 enables int
+			    2   = CRCR - 1 enables crc error register
+			    4,3 = SIZE - 0 32byte, 1 64 byte, 2 128 byte, 3, 256 byte
+			    5   = SLEEP- - 0 means disabled, 1 means enabled?
+			    6   = H/S - comm speed - 0 = clk / 16, 1 = clk / 8
+			    7   = unused
+			*/
 			LOGMASKED(LOG_REG_WRITES, "%s: Control Register write %02x\n", machine().describe_context(), data);
-			// TODO: This is a literal translation of the previous device behaviour, and is incorrect.
-			// Namely it can't possibly ping irq state on the fly, needs some transaction from the receiver.
-			const int old_state = m_irq_state;
-			if (BIT(data, 5))
-			{
-				LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Asserting IRQ\n", machine().describe_context());
-				m_irq_state = ASSERT_LINE;
-			}
-			if (!BIT(data, 0))
-			{
-				LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Clearing IRQ\n", machine().describe_context());
-				m_irq_state = CLEAR_LINE;
-			}
-			if (old_state != m_irq_state)
-			{
-				m_irq_cb(m_irq_state);
-			}
+			set_ctrl(data);
 		})
 	);
 	map(0x02, 0x02).lw8(
 		NAME([this] (offs_t offset, u8 data) {
+			/*
+			sub-id register bits:
+			    1,0     = SID, sub-id
+			    3,2     = MSID, master sub-id
+			    7,6,5,4 = unused
+			*/
 			LOGMASKED(LOG_REG_WRITES, "%s: regs_w: Sub ID Register = %02x\n", machine().describe_context(), data);
 		})
 	);
 }
 
-u32 k056230_device::ram_r(offs_t offset, u32 mem_mask)
+u8 k056230_device::ram_r(offs_t offset)
 {
-	const auto lanc_ram = util::big_endian_cast<const u32>(m_ram.target());
-	u32 data = lanc_ram[offset & 0x7ff];
-	LOGMASKED(LOG_RAM_READS, "%s: Network RAM read [%04x (%03x)]: %08x & %08x\n", machine().describe_context(), offset << 2, (offset & 0x7ff) << 2, data, mem_mask);
+	const auto lanc_ram = (u8*)m_ram.target();
+	u8 data = lanc_ram[offset & 0x1fff];
+	if (!machine().side_effects_disabled())
+		LOGMASKED(LOG_RAM_READS, "%s: Network RAM read [%04x (%04x)]: %02x\n", machine().describe_context(), offset, offset & 0x1fff, data);
 	return data;
 }
 
-void k056230_device::ram_w(offs_t offset, u32 data, u32 mem_mask)
+void k056230_device::ram_w(offs_t offset, u8 data)
 {
-	const auto lanc_ram = util::big_endian_cast<u32>(m_ram.target());
-	LOGMASKED(LOG_RAM_WRITES, "%s: Network RAM write [%04x (%03x)] = %08x & %08x\n", machine().describe_context(), offset << 2, (offset & 0x7ff) << 2, data, mem_mask);
-	COMBINE_DATA(&lanc_ram[offset & 0x7ff]);
+	const auto lanc_ram = (u8*)m_ram.target();
+	LOGMASKED(LOG_RAM_WRITES, "%s: Network RAM write [%04x (%04x)] = %02x\n", machine().describe_context(), offset, offset & 0x1fff, data);
+	lanc_ram[offset & 0x1fff] = data;
 }
 
+void k056230_device::set_irq(int state)
+{
+	if (state != m_irq_state)
+	{
+		if (state == CLEAR_LINE)
+			m_status |= 0x10;
+		else
+			m_status &= 0xef;
+
+		m_irq_state = state;
+
+		if (m_irq_enable)
+			m_irq_cb(m_irq_state);
+	}
+}
+
+void k056230_device::set_mode(u8 data)
+{
+	m_linkid = data & 0x07;
+	m_linkidm = (data & 0x18) >> 3;
+	if (m_linkidm == 2)
+		logerror("set_mode: %02x invalid IDM selected\n", data);
+	m_linkmaster = bool(BIT(data, 5));
+	// ignore bit 6 (TXD) for now
+	if (data & 0x80)
+		logerror("set_mode: %02x manual tx/rx mode NOT implemented\n", data);
+}
+
+void k056230_device::set_ctrl(u8 data)
+{
+	bool start = bool(BIT(data, 0));
+	if (!bool(BIT(data, 1)))
+	{
+		set_irq(CLEAR_LINE);
+	}
+	m_irq_enable = bool(BIT(data, 1));
+	// ignore bit 2 (CRCR) for now
+	m_linksize = (data & 0x18) >> 3;
+	m_linkenable = bool(BIT(data, 5));
+	// ignore bit 6 (H/S) for now
+	// ignore bit 7 (unused)
+
+	if (m_linkenable)
+	{
+		if (m_linkid == 0x00)
+		{
+			if (start)
+			{
+				// master (start)
+				m_txmode = 0x01;
+				m_status |= 0x20;
+			}
+			else
+			{
+				// master (stop)
+				m_txmode = 0x02;
+				m_status &= 0xdf;
+			}
+		}
+		else
+		{
+			// slave
+			m_txmode = 0x03;
+			m_status |= 0x20;
+		}
+	} else {
+		// (disabled)
+		m_status &= 0xdf;
+		m_txmode = 0x00;
+	}
+}
+
+TIMER_CALLBACK_MEMBER(k056230_device::tick_timer_callback)
+{
+	comm_tick();
+}
+
+void k056230_device::comm_tick()
+{
+	m_context->check_sockets();
+
+	if (m_linkenable)
+	{
+		// if both sockets are there check ring
+		if (m_context->connected())
+		{
+			unsigned frame_size = 1 << (5 + m_linksize);
+			unsigned data_size = frame_size + 1;
+
+			bool raise_irq = (m_irq_state == ASSERT_LINE);
+
+			if (m_txmode >= 0x00)
+			{
+				// try to read one message
+				unsigned recv = read_frame(data_size);
+				while (recv > 0)
+				{
+					// check if valid id
+					u8 idx = m_buffer[0];
+
+					if (idx <= 0x07)
+					{
+						// if not own message
+						if ((idx | m_linkidm) != (m_linkid | m_linkidm))
+						{
+							// save message to ram
+							unsigned frame_start = idx * 0x0100;
+
+							const auto lanc_ram = (u8*)m_ram.target();
+							std::copy_n(&m_buffer[1], frame_size, &lanc_ram[frame_start]);
+
+							// forward message to other nodes
+							send_frame(data_size);
+						}
+
+						if (idx == 0)
+							m_txmode &= 0xfd;
+					}
+
+					// try to read another message
+					recv = read_frame(data_size);
+				}
+			}
+
+			if (m_txmode == 0x01)
+			{
+				// send local data to network
+				for (unsigned j = 0; j <= m_linkidm; j++)
+				{
+					comm_send(m_linkid + j, frame_size, data_size);
+				}
+
+				// disable transmission
+				m_txmode = 0x02;
+
+				raise_irq = true;
+			}
+
+			// raise irq
+			if (raise_irq)
+			{
+				set_irq(ASSERT_LINE);
+			}
+		}
+	}
+}
+
+void k056230_device::comm_send(u8 idx, unsigned frame_size, unsigned data_size)
+{
+	unsigned frame_start = idx * 0x100;
+
+	m_buffer[0] = idx;
+	const auto lanc_ram = (u8*)m_ram.target();
+	std::copy_n(&lanc_ram[frame_start], frame_size, &m_buffer[1]);
+
+	send_frame(data_size);
+}
+
+unsigned k056230_device::read_frame(unsigned data_size)
+{
+	unsigned bytes_read = m_context->receive(&m_buffer[0], data_size);
+	if (bytes_read == UINT_MAX)
+	{
+		// error case, do nothing
+		return 0;
+	}
+	return bytes_read;
+}
+
+void k056230_device::send_frame(unsigned data_size)
+{
+	unsigned bytes_sent = m_context->send(&m_buffer[0], data_size);
+	if (bytes_sent == UINT_MAX)
+	{
+		// error case, do nothing
+	}
+}
+
+
 /****************************************
  *
  * konami/viper.cpp superset overrides
@@ -134,7 +839,6 @@ void k056230_viper_device::device_reset()
 {
 	k056230_device::device_reset();
 	m_control = 0;
-	m_irq_enable = false;
 	m_unk[0] = m_unk[1] = 0;
 }
 
@@ -155,7 +859,7 @@ void k056230_viper_device::regs_map(address_map &map)
 			}
 			else
 			{
-				if(m_irq_enable)
+				if (m_irq_enable)
 					m_irq_state = ASSERT_LINE;
 			}
 
@@ -171,14 +875,16 @@ void k056230_viper_device::regs_map(address_map &map)
 	);
 	map(0x02, 0x02).lr8(
 		NAME([this] (offs_t offset) {
-			LOGMASKED(LOG_REG_READS, "%s: status_r: %02x\n", machine().describe_context(), m_status);
+			if (!machine().side_effects_disabled())
+				LOGMASKED(LOG_REG_READS, "%s: status_r: %02x\n", machine().describe_context(), m_status);
 			return m_status;
 		})
 	);
 	// TODO: unknown regs
 	map(0x03, 0x04).lrw8(
 		NAME([this] (offs_t offset) {
-			LOGMASKED(LOG_REG_READS, "%s: unk%d_r\n", machine().describe_context(), offset + 3, m_unk[offset]);
+			if (!machine().side_effects_disabled())
+				LOGMASKED(LOG_REG_READS, "%s: unk%d_r\n", machine().describe_context(), offset + 3, m_unk[offset]);
 			return m_unk[offset];
 		}),
 		NAME([this] (offs_t offset, u8 data) {
@@ -194,4 +900,3 @@ void k056230_viper_device::regs_map(address_map &map)
 		})
 	);
 }
-
diff --git a/src/devices/machine/k056230.h b/src/devices/machine/k056230.h
index 35e847aae2a8f..0c1f4b35928ee 100644
--- a/src/devices/machine/k056230.h
+++ b/src/devices/machine/k056230.h
@@ -1,8 +1,8 @@
 // license:BSD-3-Clause
-// copyright-holders:Fabio Priuli
+// copyright-holders:Fabio Priuli, Ariane Fugmann
 /***************************************************************************
 
-    Konami 056230 LAN controller skeleton device
+    Konami 056230 LAN controller device
 
 ***************************************************************************/
 
@@ -11,32 +11,58 @@
 
 #pragma once
 
+
 class k056230_device : public device_t
 {
 public:
 	// construction/destruction
-	k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+	k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0U);
 
 	auto irq_cb() { return m_irq_cb.bind(); }
 
-	u32 ram_r(offs_t offset, u32 mem_mask = ~0);
-	void ram_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+	u8 ram_r(offs_t offset);
+	void ram_w(offs_t offset, u8 data);
 
 	virtual void regs_map(address_map &map) ATTR_COLD;
 
 protected:
-	k056230_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+	k056230_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
 
 	// device-level overrides
 	virtual void device_start() override ATTR_COLD;
+	virtual void device_stop() override ATTR_COLD;
 	virtual void device_reset() override ATTR_COLD;
 
-	memory_share_creator<u32> m_ram;
+	memory_share_creator<u8> m_ram;
 
 	devcb_write_line m_irq_cb;
-	int m_irq_state = 0;
-	u8 m_ctrl_reg = 0;
-	u8 m_status = 0;
+	bool m_irq_enable;
+	int m_irq_state;
+	u8 m_status;
+
+private:
+	emu_timer *m_tick_timer;
+
+	class context;
+	std::unique_ptr<context> m_context;
+
+	u8 m_buffer[0x101];
+	bool m_linkenable;
+	bool m_linkmaster;
+	u8 m_linkid;
+	u8 m_linkidm;
+	u8 m_linksize;
+	u8 m_txmode;
+
+	TIMER_CALLBACK_MEMBER(tick_timer_callback);
+
+	void set_irq(int state);
+	void set_mode(u8 data);
+	void set_ctrl(u8 data);
+	void comm_tick();
+	void comm_send(u8 idx, unsigned frame_size, unsigned data_size);
+	unsigned read_frame(unsigned data_size);
+	void send_frame(unsigned data_size);
 };
 
 class k056230_viper_device : public k056230_device
@@ -51,9 +77,8 @@ class k056230_viper_device : public k056230_device
 	virtual void device_reset() override ATTR_COLD;
 
 private:
-	u8 m_control = 0;
-	bool m_irq_enable = false;
-	u8 m_unk[2]{};
+	u8 m_control;
+	u8 m_unk[2];
 };
 
 // device type definition
diff --git a/src/mame/konami/gticlub.cpp b/src/mame/konami/gticlub.cpp
index fa6db848efdac..2c5d20c722fd8 100644
--- a/src/mame/konami/gticlub.cpp
+++ b/src/mame/konami/gticlub.cpp
@@ -902,7 +902,7 @@ void gticlub_state::gticlub(machine_config &config)
 	m_adc1038->set_input_callback(FUNC(gticlub_state::adc1038_input_callback));
 	m_adc1038->set_gti_club_hack(true);
 
-	K056230(config, m_k056230);
+	K056230(config, m_k056230, 0U);
 	m_k056230->irq_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ2);
 
 	// video hardware
@@ -985,7 +985,7 @@ void hangplt_state::hangplt(machine_config &config)
 	ADC1038(config, m_adc1038, 0);
 	m_adc1038->set_input_callback(FUNC(hangplt_state::adc1038_input_callback));
 
-	K056230(config, m_k056230);
+	K056230(config, m_k056230, 0U);
 	m_k056230->irq_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ2);
 
 	VOODOO_1(config, m_voodoo[0], voodoo_1_device::NOMINAL_CLOCK);
@@ -1418,12 +1418,12 @@ void hangplt_state::init_hangpltu()
 
 /*************************************************************************/
 
-GAME( 1996, gticlub,    0,        gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver EAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
-GAME( 1996, gticlubu,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver UAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
-GAME( 1996, gticluba,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver AAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
-GAME( 1996, gticlubj,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver JAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
-GAME( 1997, thunderh,   0,        thunderh, thunderh, thunderh_state, init_gticlub,  ROT0, "Konami", "Operation Thunder Hurricane (ver EAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
-GAME( 1997, thunderhu,  thunderh, thunderh, thunderh, thunderh_state, init_gticlub,  ROT0, "Konami", "Operation Thunder Hurricane (ver UAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_NODEVICE_LAN )
+GAME( 1996, gticlub,    0,        gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver EAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+GAME( 1996, gticlubu,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver UAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+GAME( 1996, gticluba,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver AAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+GAME( 1996, gticlubj,   gticlub,  gticlub,  gticlub,  gticlub_state,  init_gticlub,  ROT0, "Konami", "GTI Club: Rally Cote D'Azur (ver JAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+GAME( 1997, thunderh,   0,        thunderh, thunderh, thunderh_state, init_gticlub,  ROT0, "Konami", "Operation Thunder Hurricane (ver EAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+GAME( 1997, thunderhu,  thunderh, thunderh, thunderh, thunderh_state, init_gticlub,  ROT0, "Konami", "Operation Thunder Hurricane (ver UAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
 GAME( 1997, slrasslt,   0,        slrasslt, slrasslt, gticlub_state,  init_gticlub,  ROT0, "Konami", "Solar Assault (ver UAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // Based on Revised code
 GAME( 1997, slrassltj,  slrasslt, slrasslt, slrasslt, gticlub_state,  init_gticlub,  ROT0, "Konami", "Solar Assault Revised (ver JAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
 GAME( 1997, slrassltj1, slrasslt, slrasslt, slrasslt, gticlub_state,  init_gticlub,  ROT0, "Konami", "Solar Assault (ver JAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
diff --git a/src/mame/konami/konamigx.cpp b/src/mame/konami/konamigx.cpp
index bb099011451fa..b1bbc2eaa6b35 100644
--- a/src/mame/konami/konamigx.cpp
+++ b/src/mame/konami/konamigx.cpp
@@ -105,7 +105,6 @@
 #include "cpu/z80/z80.h"
 #include "machine/eepromser.h"
 #include "sound/k054539.h"
-//#include "machine/k056230.h"
 #include "sound/k056800.h"
 #include "sound/okim6295.h"
 #include "speaker.h"
@@ -1085,8 +1084,8 @@ void konamigx_state::gx_type1_map(address_map &map)
 void konamigx_state::racinfrc_map(address_map &map)
 {
 	gx_type1_map(map);
-	map(0xdc0000, 0xdc1fff).ram();         // 056230 RAM?
-	map(0xdd0000, 0xdd00ff).nopr().nopw(); // 056230 regs?
+	map(0xdc0000, 0xdc1fff).rw(m_k056230, FUNC(k056230_device::ram_r), FUNC(k056230_device::ram_w));
+	map(0xdd0000, 0xdd00ff).m(m_k056230, FUNC(k056230_device::regs_map));
 }
 
 void konamigx_state::gx_type2_map(address_map &map)
@@ -1917,6 +1916,9 @@ void konamigx_state::racinfrc(machine_config &config)
 
 	adc0834_device &adc(ADC0834(config, "adc0834", 0));
 	adc.set_input_callback(FUNC(konamigx_state::adc0834_callback));
+
+	K056230(config, m_k056230, 0U);
+	m_k056230->irq_cb().set_inputline(m_maincpu, M68K_IRQ_5);
 }
 
 void konamigx_state::gxtype3(machine_config &config)
@@ -4201,8 +4203,8 @@ GAME( 1994, konamigx,  0,        konamigx_bios, common,   konamigx_state, init_k
    needs the ROZ layer to be playable
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
 
-GAME( 1994, racinfrc,  konamigx, racinfrc,      racinfrc, konamigx_state, init_posthack, ROT0, "Konami", "Racin' Force (ver EAC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_NODEVICE_LAN )
-GAME( 1994, racinfrcu, racinfrc, racinfrc,      racinfrc, konamigx_state, init_posthack, ROT0, "Konami", "Racin' Force (ver UAB)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_NODEVICE_LAN )
+GAME( 1994, racinfrc,  konamigx, racinfrc,      racinfrc, konamigx_state, init_posthack, ROT0, "Konami", "Racin' Force (ver EAC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
+GAME( 1994, racinfrcu, racinfrc, racinfrc,      racinfrc, konamigx_state, init_posthack, ROT0, "Konami", "Racin' Force (ver UAB)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
 
 GAME( 1994, opengolf,  konamigx, opengolf,      opengolf, konamigx_state, init_posthack, ROT0, "Konami", "Konami's Open Golf Championship (ver EAE)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING  )
 GAME( 1994, opengolf2, opengolf, opengolf,      opengolf, konamigx_state, init_posthack, ROT0, "Konami", "Konami's Open Golf Championship (ver EAD)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING  )
diff --git a/src/mame/konami/konamigx.h b/src/mame/konami/konamigx.h
index 82d9601d1a7c5..c7117636b874a 100644
--- a/src/mame/konami/konamigx.h
+++ b/src/mame/konami/konamigx.h
@@ -14,6 +14,7 @@
 #include "cpu/tms57002/tms57002.h"
 #include "machine/adc083x.h"
 #include "machine/k053252.h"
+#include "machine/k056230.h"
 #include "machine/timer.h"
 #include "sound/k054539.h"
 #include "sound/k056800.h"
@@ -35,6 +36,7 @@ class konamigx_state : public driver_device
 		, m_k053252(*this, "k053252")
 		, m_k055673(*this, "k055673")
 		, m_k055555(*this, "k055555")
+		, m_k056230(*this, "k056230")
 		, m_k056832(*this, "k056832")
 		, m_k054338(*this, "k054338")
 		, m_k056800(*this, "k056800")
@@ -212,6 +214,7 @@ class konamigx_state : public driver_device
 	optional_device<k053252_device> m_k053252;
 	required_device<k055673_device> m_k055673;
 	required_device<k055555_device> m_k055555;
+	optional_device<k056230_device> m_k056230;
 	required_device<k056832_device> m_k056832;
 	optional_device<k054338_device> m_k054338;
 	optional_device<k056800_device> m_k056800;
diff --git a/src/mame/konami/plygonet.cpp b/src/mame/konami/plygonet.cpp
index 8f7940e213a54..c113911b151ac 100644
--- a/src/mame/konami/plygonet.cpp
+++ b/src/mame/konami/plygonet.cpp
@@ -30,9 +30,6 @@
     - Controls
     - Palettes
 
-    Driver needs:
-    - Network at 580800 (K056230)
-
     Tech info by Phil Bennett, from the schematics:
 
     68000 address map
@@ -1058,7 +1055,7 @@ void polygonet_state::plygonet(machine_config &config)
 	WATCHDOG_TIMER(config, m_watchdog);
 
 	// Networking hardware
-	K056230(config, m_k056230);
+	K056230(config, m_k056230, 0U);
 	m_k056230->irq_cb().set_inputline(m_maincpu, M68K_IRQ_3);
 
 	// Video hardware
@@ -1147,5 +1144,5 @@ ROM_END
 //-------------------------------------------------
 
 //    YEAR  NAME      PARENT   MACHINE   INPUT      STATE            INIT
-GAME( 1993, plygonet, 0,       plygonet, polygonet, polygonet_state, empty_init, ROT90, "Konami", "Polygonet Commanders (ver UAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE | MACHINE_NODEVICE_LAN )
-GAME( 1993, polynetw, 0,       plygonet, polynetw,  polygonet_state, empty_init, ROT90, "Konami", "Poly-Net Warriors (ver JAA)",    MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE | MACHINE_NODEVICE_LAN )
+GAME( 1993, plygonet, 0,       plygonet, polygonet, polygonet_state, empty_init, ROT90, "Konami", "Polygonet Commanders (ver UAA)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+GAME( 1993, polynetw, 0,       plygonet, polynetw,  polygonet_state, empty_init, ROT90, "Konami", "Poly-Net Warriors (ver JAA)",    MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/konami/viper.cpp b/src/mame/konami/viper.cpp
index 1bbfaf1543372..261bb1c9695c5 100644
--- a/src/mame/konami/viper.cpp
+++ b/src/mame/konami/viper.cpp
@@ -2583,7 +2583,7 @@ void viper_state::viper(machine_config &config)
 	NS16550(config, "duart_com:chan0", XTAL(19'660'800));
 	NS16550(config, "duart_com:chan1", XTAL(19'660'800)).out_int_callback().set(FUNC(viper_state::uart_int));
 
-	K056230_VIPER(config, m_lanc);
+	K056230_VIPER(config, m_lanc, 0U);
 	m_lanc->irq_cb().set(FUNC(viper_state::lanc_int));
 
 	VOODOO_3(config, m_voodoo, voodoo_3_device::NOMINAL_CLOCK);
diff --git a/src/mame/konami/zr107.cpp b/src/mame/konami/zr107.cpp
index 8d3eb6486eb94..f19fdd5c049d7 100644
--- a/src/mame/konami/zr107.cpp
+++ b/src/mame/konami/zr107.cpp
@@ -758,7 +758,7 @@ void zr107_state::zr107(machine_config &config)
 
 	EEPROM_93C46_16BIT(config, "eeprom");
 
-	K056230(config, m_k056230);
+	K056230(config, m_k056230, 0U);
 	m_k056230->irq_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ2);
 
 	WATCHDOG_TIMER(config, m_watchdog);
@@ -1143,14 +1143,14 @@ ROM_END
 
 /*****************************************************************************/
 
-GAME( 1995, midnrun,   0,        midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (EAA, Euro v1.11)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1995, midnrunj,  midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (JAD, Japan v1.10)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1995, midnruna,  midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (AAA, Asia v1.10, older sound program)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1995, midnruna2, midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (AAA, Asia v1.10, newer sound program)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, windheat,  0,        midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (EAA, Euro v2.11)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, windheatu, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (UBC, USA v2.22)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, windheatj, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (JAA, Japan v2.11)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, windheata, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (AAA, Asia v2.11)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, jetwave,   0,        jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Jet Wave (EAB, Euro v1.04)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, waveshrk,  jetwave,  jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Wave Shark (UAB, USA v1.04)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
-GAME( 1996, jetwavej,  jetwave,  jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Jet Wave (JAB, Japan v1.04)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NODEVICE_LAN )
+GAME( 1995, midnrun,   0,        midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (EAA, Euro v1.11)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, midnrunj,  midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (JAD, Japan v1.10)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, midnruna,  midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (AAA, Asia v1.10, older sound program)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, midnruna2, midnrun,  midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Midnight Run: Road Fighter 2 (AAA, Asia v1.10, newer sound program)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, windheat,  0,        midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (EAA, Euro v2.11)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, windheatu, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (UBC, USA v2.22)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, windheatj, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (JAA, Japan v2.11)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, windheata, windheat, midnrun, midnrun,  midnrun_state, driver_init,  ROT0, "Konami", "Winding Heat (AAA, Asia v2.11)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, jetwave,   0,        jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Jet Wave (EAB, Euro v1.04)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, waveshrk,  jetwave,  jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Wave Shark (UAB, USA v1.04)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, jetwavej,  jetwave,  jetwave, jetwave,  jetwave_state, driver_init,  ROT0, "Konami", "Jet Wave (JAB, Japan v1.04)", MACHINE_IMPERFECT_GRAPHICS )