diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 1034351992..358f39900c 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -203,8 +203,9 @@ add_library(core
HW/EXI/EXI_DeviceAGP.h
HW/EXI/EXI_DeviceDummy.cpp
HW/EXI/EXI_DeviceDummy.h
- HW/EXI/EXI_DeviceEthernet.cpp
- HW/EXI/EXI_DeviceEthernet.h
+ HW/EXI/EXI_DeviceEthernetBase.cpp
+ HW/EXI/EXI_DeviceEthernetBase.h
+ HW/EXI/EXI_DeviceEthernetTAP.h
HW/EXI/EXI_DeviceGecko.cpp
HW/EXI/EXI_DeviceGecko.h
HW/EXI/EXI_DeviceIPL.cpp
@@ -589,8 +590,8 @@ endif()
if(WIN32)
target_sources(core PRIVATE
- HW/EXI/BBA-TAP/TAP_Win32.cpp
- HW/EXI/BBA-TAP/TAP_Win32.h
+ HW/EXI/EXI_DeviceEthernetTap_Win32.cpp
+ HW/EXI/EXI_DeviceEthernetTap_Win32.h
HW/WiimoteReal/IOWin.cpp
HW/WiimoteReal/IOWin.h
)
@@ -603,7 +604,7 @@ if(WIN32)
target_compile_definitions(core PRIVATE "-D_WINSOCK_DEPRECATED_NO_WARNINGS")
elseif(APPLE)
target_sources(core PRIVATE
- HW/EXI/BBA-TAP/TAP_Apple.cpp
+ HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
HW/WiimoteReal/IOdarwin.h
HW/WiimoteReal/IOdarwin_private.h
HW/WiimoteReal/IOdarwin.mm
@@ -611,7 +612,7 @@ elseif(APPLE)
target_link_libraries(core PUBLIC ${IOB_LIBRARY})
elseif(UNIX)
target_sources(core PRIVATE
- HW/EXI/BBA-TAP/TAP_Unix.cpp
+ HW/EXI/EXI_DeviceEthernetTAP_Unix.cpp
)
if(ANDROID)
target_sources(core PRIVATE
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index a08761f0d9..30e5781cda 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -132,14 +132,14 @@
-
-
+
+
@@ -404,14 +404,15 @@
-
-
+
+
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 3064754798..27f1539adf 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -442,7 +442,13 @@
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
+
+ HW %28Flipper/Hollywood%29\EXI - Expansion Interface
+
+
+ HW %28Flipper/Hollywood%29\EXI - Expansion Interface
+
+
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
@@ -457,9 +463,6 @@
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
- HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
@@ -1157,7 +1160,13 @@
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
+
+ HW %28Flipper/Hollywood%29\EXI - Expansion Interface
+
+
+ HW %28Flipper/Hollywood%29\EXI - Expansion Interface
+
+
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
@@ -1172,9 +1181,6 @@
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
- HW %28Flipper/Hollywood%29\EXI - Expansion Interface
-
HW %28Flipper/Hollywood%29\EXI - Expansion Interface
diff --git a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Apple.cpp b/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Apple.cpp
deleted file mode 100644
index 6dbed04f20..0000000000
--- a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Apple.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2008 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include
-#include
-
-#include "Common/Logging/Log.h"
-#include "Common/StringUtil.h"
-#include "Core/HW/EXI/EXI_Device.h"
-#include "Core/HW/EXI/EXI_DeviceEthernet.h"
-
-namespace ExpansionInterface
-{
-bool CEXIETHERNET::Activate()
-{
- if (IsActivated())
- return true;
-
- // Assumes TunTap OS X is installed, and /dev/tun0 is not in use
- // and readable / writable by the logged-in user
-
- if ((fd = open("/dev/tap0", O_RDWR)) < 0)
- {
- ERROR_LOG(SP1, "Couldn't open /dev/tap0, unable to init BBA");
- return false;
- }
-
- INFO_LOG(SP1, "BBA initialized.");
- return RecvInit();
-}
-
-void CEXIETHERNET::Deactivate()
-{
- close(fd);
- fd = -1;
-
- readEnabled.Clear();
- readThreadShutdown.Set();
- if (readThread.joinable())
- readThread.join();
-}
-
-bool CEXIETHERNET::IsActivated()
-{
- return fd != -1;
-}
-
-bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
-{
- INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str());
-
- int writtenBytes = write(fd, frame, size);
- if ((u32)writtenBytes != size)
- {
- ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes);
- return false;
- }
- else
- {
- SendComplete();
- return true;
- }
-}
-
-void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
-{
- while (!self->readThreadShutdown.IsSet())
- {
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(self->fd, &rfds);
-
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 50000;
- if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0)
- continue;
-
- int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE);
- if (readBytes < 0)
- {
- ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes);
- }
- else if (self->readEnabled.IsSet())
- {
- INFO_LOG(SP1, "Read data: %s",
- ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str());
- self->mRecvBufferLength = readBytes;
- self->RecvHandlePacket();
- }
- }
-}
-
-bool CEXIETHERNET::RecvInit()
-{
- readThread = std::thread(ReadThreadHandler, this);
- return true;
-}
-
-void CEXIETHERNET::RecvStart()
-{
- readEnabled.Set();
-}
-
-void CEXIETHERNET::RecvStop()
-{
- readEnabled.Clear();
-}
-} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/EXI_Device.cpp b/Source/Core/Core/HW/EXI/EXI_Device.cpp
index be4a7029c8..e1fe49886e 100644
--- a/Source/Core/Core/HW/EXI/EXI_Device.cpp
+++ b/Source/Core/Core/HW/EXI/EXI_Device.cpp
@@ -10,7 +10,7 @@
#include "Core/HW/EXI/EXI_DeviceAD16.h"
#include "Core/HW/EXI/EXI_DeviceAGP.h"
#include "Core/HW/EXI/EXI_DeviceDummy.h"
-#include "Core/HW/EXI/EXI_DeviceEthernet.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
#include "Core/HW/EXI/EXI_DeviceGecko.h"
#include "Core/HW/EXI/EXI_DeviceIPL.h"
#include "Core/HW/EXI/EXI_DeviceMemoryCard.h"
@@ -131,8 +131,8 @@ std::unique_ptr EXIDevice_Create(const TEXIDevices device_type, cons
result = std::make_unique(channel_num);
break;
- case EXIDEVICE_ETH:
- result = std::make_unique();
+ case EXIDEVICE_ETH_TAP:
+ result = std::make_unique();
break;
case EXIDEVICE_GECKO:
diff --git a/Source/Core/Core/HW/EXI/EXI_Device.h b/Source/Core/Core/HW/EXI/EXI_Device.h
index 0eb30904ca..6670bfbbe2 100644
--- a/Source/Core/Core/HW/EXI/EXI_Device.h
+++ b/Source/Core/Core/HW/EXI/EXI_Device.h
@@ -18,7 +18,7 @@ enum TEXIDevices : int
EXIDEVICE_MASKROM,
EXIDEVICE_AD16,
EXIDEVICE_MIC,
- EXIDEVICE_ETH,
+ EXIDEVICE_ETH_TAP,
// Was used for Triforce in the past, but the implementation is no longer in Dolphin.
// It's kept here so that values below will stay constant.
EXIDEVICE_AM_BASEBOARD,
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.cpp
similarity index 70%
rename from Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp
rename to Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.cpp
index 1972e3e3ea..7948bfc371 100644
--- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.cpp
@@ -2,11 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-#include "Core/HW/EXI/EXI_DeviceEthernet.h"
-
-#include
-#include
-#include
+#include "Core/HW/EXI/EXI_DeviceEthernetBase.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
@@ -22,40 +18,42 @@ namespace ExpansionInterface
// XXX: The BBA stores multi-byte elements as little endian.
// Multiple parts of this implementation depend on Dolphin
// being compiled for a little endian host.
-
-CEXIETHERNET::CEXIETHERNET()
+CEXIEthernetBase::CEXIEthernetBase()
{
- tx_fifo = std::make_unique(BBA_TXFIFO_SIZE);
- mBbaMem = std::make_unique(BBA_MEM_SIZE);
- mRecvBuffer = std::make_unique(BBA_RECV_SIZE);
-
MXHardReset();
// Parse MAC address from config, and generate a new one if it doesn't
// exist or can't be parsed.
- std::string& mac_addr_setting = SConfig::GetInstance().m_bba_mac;
- std::optional mac_addr = Common::StringToMacAddress(mac_addr_setting);
+ const std::string& mac_addr_setting = SConfig::GetInstance().m_bba_mac;
+ Common::MACAddress mac_addr;
- if (!mac_addr)
+ if (mac_addr_setting.empty())
{
mac_addr = Common::GenerateMacAddress(Common::MACConsumer::BBA);
- mac_addr_setting = Common::MacAddressToString(mac_addr.value());
- SConfig::GetInstance().SaveSettings();
+ }
+ else
+ {
+ std::optional parsed = Common::StringToMacAddress(mac_addr_setting);
+
+ if (!parsed)
+ {
+ mac_addr = Common::GenerateMacAddress(Common::MACConsumer::BBA);
+ ERROR_LOG(SP1, "Invalid mac address (%s), generated a temporary one (%s)",
+ mac_addr_setting.c_str(), Common::MacAddressToString(mac_addr).c_str());
+ }
+ else
+ {
+ mac_addr = parsed.value();
+ }
}
- const auto& mac = mac_addr.value();
- memcpy(&mBbaMem[BBA_NAFR_PAR0], mac.data(), mac.size());
+ memcpy(&m_bba_mem.nafr_par, mac_addr.data(), mac_addr.size());
// HACK: .. fully established 100BASE-T link
- mBbaMem[BBA_NWAYS] = NWAYS_LS100 | NWAYS_LPNWAY | NWAYS_100TXF | NWAYS_ANCLPT;
+ m_bba_mem.nways = NWAYS_LS100 | NWAYS_LPNWAY | NWAYS_100TXF | NWAYS_ANCLPT;
}
-CEXIETHERNET::~CEXIETHERNET()
-{
- Deactivate();
-}
-
-void CEXIETHERNET::SetCS(int cs)
+void CEXIEthernetBase::SetCS(int cs)
{
if (cs)
{
@@ -64,17 +62,17 @@ void CEXIETHERNET::SetCS(int cs)
}
}
-bool CEXIETHERNET::IsPresent() const
+bool CEXIEthernetBase::IsPresent() const
{
return true;
}
-bool CEXIETHERNET::IsInterruptSet()
+bool CEXIEthernetBase::IsInterruptSet()
{
return !!(exi_status.interrupt & exi_status.interrupt_mask);
}
-void CEXIETHERNET::ImmWrite(u32 data, u32 size)
+void CEXIEthernetBase::ImmWrite(u32 data, u32 size)
{
data >>= (4 - size) * 8;
@@ -125,7 +123,7 @@ void CEXIETHERNET::ImmWrite(u32 data, u32 size)
}
}
-u32 CEXIETHERNET::ImmRead(u32 size)
+u32 CEXIEthernetBase::ImmRead(u32 size)
{
u32 ret = 0;
@@ -155,7 +153,7 @@ u32 CEXIETHERNET::ImmRead(u32 size)
else
{
for (int i = size - 1; i >= 0; i--)
- ret |= mBbaMem[transfer.address++] << (i * 8);
+ ret |= m_bba_mem.raw[transfer.address++] << (i * 8);
}
DEBUG_LOG(SP1, "imm r%i: %0*x", size, size * 2, ret);
@@ -165,7 +163,7 @@ u32 CEXIETHERNET::ImmRead(u32 size)
return ret;
}
-void CEXIETHERNET::DMAWrite(u32 addr, u32 size)
+void CEXIEthernetBase::DMAWrite(u32 addr, u32 size)
{
DEBUG_LOG(SP1, "DMA write: %08x %x", addr, size);
@@ -182,32 +180,32 @@ void CEXIETHERNET::DMAWrite(u32 addr, u32 size)
}
}
-void CEXIETHERNET::DMARead(u32 addr, u32 size)
+void CEXIEthernetBase::DMARead(u32 addr, u32 size)
{
DEBUG_LOG(SP1, "DMA read: %08x %x", addr, size);
- Memory::CopyToEmu(addr, &mBbaMem[transfer.address], size);
+ Memory::CopyToEmu(addr, &m_bba_mem.raw[transfer.address], size);
transfer.address += size;
}
-void CEXIETHERNET::DoState(PointerWrap& p)
+void CEXIEthernetBase::DoState(PointerWrap& p)
{
- p.DoArray(tx_fifo.get(), BBA_TXFIFO_SIZE);
- p.DoArray(mBbaMem.get(), BBA_MEM_SIZE);
+ p.DoArray(&m_tx_fifo, BBA_TXFIFO_SIZE);
+ p.DoArray(&m_bba_mem.raw, BBA_MEM_SIZE);
}
-bool CEXIETHERNET::IsMXCommand(u32 const data)
+bool CEXIEthernetBase::IsMXCommand(u32 const data)
{
return !!(data & (1 << 31));
}
-bool CEXIETHERNET::IsWriteCommand(u32 const data)
+bool CEXIEthernetBase::IsWriteCommand(u32 const data)
{
return IsMXCommand(data) ? !!(data & (1 << 30)) : !!(data & (1 << 14));
}
-const char* CEXIETHERNET::GetRegisterName() const
+const char* CEXIEthernetBase::GetRegisterName() const
{
#define STR_RETURN(x) \
case x: \
@@ -285,16 +283,16 @@ const char* CEXIETHERNET::GetRegisterName() const
#undef STR_RETURN
}
-void CEXIETHERNET::MXHardReset()
+void CEXIEthernetBase::MXHardReset()
{
- memset(mBbaMem.get(), 0, BBA_MEM_SIZE);
+ memset(&m_bba_mem.raw, 0, BBA_MEM_SIZE);
- mBbaMem[BBA_NCRB] = NCRB_PR;
- mBbaMem[BBA_NWAYC] = NWAYC_LTE | NWAYC_ANE;
- mBbaMem[BBA_MISC] = MISC1_TPF | MISC1_TPH | MISC1_TXF | MISC1_TXH;
+ m_bba_mem.ncrb = NCRB_PR;
+ m_bba_mem.nwayc = NWAYC_LTE | NWAYC_ANE;
+ m_bba_mem.misc = MISC1_TPF | MISC1_TPH | MISC1_TXF | MISC1_TXH;
}
-void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
+void CEXIEthernetBase::MXCommandHandler(u32 data, u32 size)
{
switch (transfer.address)
{
@@ -306,7 +304,7 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
Activate();
}
- if ((mBbaMem[BBA_NCRA] & NCRA_SR) ^ (data & NCRA_SR))
+ if ((m_bba_mem.ncra & NCRA_SR) ^ (data & NCRA_SR))
{
DEBUG_LOG(SP1, "%s rx", (data & NCRA_SR) ? "start" : "stop");
@@ -317,7 +315,7 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
}
// Only start transfer if there isn't one currently running
- if (!(mBbaMem[BBA_NCRA] & (NCRA_ST0 | NCRA_ST1)))
+ if (!(m_bba_mem.ncra & (NCRA_ST0 | NCRA_ST1)))
{
// Technically transfer DMA status is kept in TXDMA - not implemented
@@ -362,55 +360,57 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
default:
for (int i = size - 1; i >= 0; i--)
{
- mBbaMem[transfer.address++] = (data >> (i * 8)) & 0xff;
+ m_bba_mem.raw[transfer.address++] = (data >> (i * 8)) & 0xff;
}
return;
}
}
-void CEXIETHERNET::DirectFIFOWrite(const u8* data, u32 size)
+void CEXIEthernetBase::DirectFIFOWrite(const u8* data, u32 size)
{
// In direct mode, the hardware handles creating the state required by the
// GMAC instead of finagling with packet descriptors and such
- u16* tx_fifo_count = (u16*)&mBbaMem[BBA_TXFIFOCNT];
+ memcpy(&m_tx_fifo[0] + m_bba_mem.txfifocnt, data, size);
- memcpy(tx_fifo.get() + *tx_fifo_count, data, size);
-
- *tx_fifo_count += size;
+ m_bba_mem.txfifocnt += size;
// TODO: not sure this mask is correct.
// However, BBA_TXFIFOCNT should never get even close to this amount,
// so it shouldn't matter
- *tx_fifo_count &= (1 << 12) - 1;
+ m_bba_mem.txfifocnt &= (1 << 12) - 1;
}
-void CEXIETHERNET::SendFromDirectFIFO()
+void CEXIEthernetBase::SendFromDirectFIFO()
{
- SendFrame(tx_fifo.get(), *(u16*)&mBbaMem[BBA_TXFIFOCNT]);
+ const auto size = m_bba_mem.txfifocnt;
+ const auto frame = &m_tx_fifo[0];
+ INFO_LOG(SP1, "SendFrame %x", size);
+ DEBUG_LOG(SP1, "%s", ArrayToString(frame, size, 0x10).c_str());
+ SendFrame(frame, size);
}
-void CEXIETHERNET::SendFromPacketBuffer()
+void CEXIEthernetBase::SendFromPacketBuffer()
{
ERROR_LOG(SP1, "tx packet buffer not implemented.");
}
-void CEXIETHERNET::SendComplete()
+void CEXIEthernetBase::SendComplete()
{
- mBbaMem[BBA_NCRA] &= ~(NCRA_ST0 | NCRA_ST1);
- *(u16*)&mBbaMem[BBA_TXFIFOCNT] = 0;
+ m_bba_mem.ncra &= ~(NCRA_ST0 | NCRA_ST1);
+ m_bba_mem.txfifocnt = 0;
- if (mBbaMem[BBA_IMR] & INT_T)
+ if (m_bba_mem.imr & INT_T)
{
- mBbaMem[BBA_IR] |= INT_T;
+ m_bba_mem.ir |= INT_T;
exi_status.interrupt |= exi_status.TRANSFER;
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, 0);
}
- mBbaMem[BBA_LTPS] = 0;
+ m_bba_mem.ltps = 0;
}
-inline u8 CEXIETHERNET::HashIndex(const u8* dest_eth_addr)
+inline u8 CEXIEthernetBase::HashIndex(const u8* dest_eth_addr) const
{
// Calculate CRC
u32 crc = 0xffffffff;
@@ -432,25 +432,25 @@ inline u8 CEXIETHERNET::HashIndex(const u8* dest_eth_addr)
return crc >> 26;
}
-inline bool CEXIETHERNET::RecvMACFilter()
+inline bool CEXIEthernetBase::RecvMACFilter() const
{
static u8 const broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// Accept all destination addrs?
- if (mBbaMem[BBA_NCRB] & NCRB_PR)
+ if (m_bba_mem.ncrb & NCRB_PR)
return true;
// Unicast?
- if ((mRecvBuffer[0] & 0x01) == 0)
+ if ((m_recv_buffer[0] & 0x01) == 0)
{
- return memcmp(mRecvBuffer.get(), &mBbaMem[BBA_NAFR_PAR0], 6) == 0;
+ return memcmp(&m_recv_buffer, &m_bba_mem.nafr_par, 6) == 0;
}
- else if (memcmp(mRecvBuffer.get(), broadcast, 6) == 0)
+ else if (memcmp(&m_recv_buffer, broadcast, 6) == 0)
{
// Accept broadcast?
- return !!(mBbaMem[BBA_NCRB] & NCRB_AB);
+ return !!(m_bba_mem.ncrb & NCRB_AB);
}
- else if (mBbaMem[BBA_NCRB] & NCRB_PM)
+ else if (m_bba_mem.ncrb & NCRB_PM)
{
// Accept all multicast
return true;
@@ -458,25 +458,26 @@ inline bool CEXIETHERNET::RecvMACFilter()
else
{
// Lookup the dest eth address in the hashmap
- u16 index = HashIndex(mRecvBuffer.get());
- return !!(mBbaMem[BBA_NAFR_MAR0 + index / 8] & (1 << (index % 8)));
+ u16 index = HashIndex(&m_recv_buffer[0]);
+ return !!(m_bba_mem.nafr_mar[index / 8] & (1 << (index % 8)));
}
}
-inline void CEXIETHERNET::inc_rwp()
+inline void CEXIEthernetBase::inc_rwp()
{
- u16* rwp = (u16*)&mBbaMem[BBA_RWP];
-
- if (*rwp + 1 == page_ptr(BBA_RHBP))
- *rwp = page_ptr(BBA_BP);
+ if (m_bba_mem.rwp + 1 == page_ptr(BBA_RHBP))
+ m_bba_mem.rwp = page_ptr(BBA_BP);
else
- (*rwp)++;
+ m_bba_mem.rwp++;
}
// This function is on the critical path for receiving data.
// Be very careful about calling into the logger and other slow things
-bool CEXIETHERNET::RecvHandlePacket()
+bool CEXIEthernetBase::RecvHandlePacket()
{
+ INFO_LOG(SP1, "RecvHandlePacket: %x", m_recv_buffer_length);
+ DEBUG_LOG(SP1, "%s", ArrayToString(&m_recv_buffer[0], m_recv_buffer_length, 0x10).c_str());
+
u8* write_ptr;
u8* end_ptr;
u8* read_ptr;
@@ -488,23 +489,23 @@ bool CEXIETHERNET::RecvHandlePacket()
goto wait_for_next;
#ifdef BBA_TRACK_PAGE_PTRS
- INFO_LOG(SP1, "RecvHandlePacket %x\n%s", mRecvBufferLength,
- ArrayToString(mRecvBuffer, mRecvBufferLength, 0x100).c_str());
+ INFO_LOG(SP1, "RecvHandlePacket %x\n%s", m_recv_buffer_length,
+ ArrayToString(m_recv_buffer, m_recv_buffer_length, 0x100).c_str());
INFO_LOG(SP1, "%x %x %x %x", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP),
page_ptr(BBA_RHBP));
#endif
- write_ptr = ptr_from_page_ptr(BBA_RWP);
- end_ptr = ptr_from_page_ptr(BBA_RHBP);
- read_ptr = ptr_from_page_ptr(BBA_RRP);
+ write_ptr = PtrFromPagePtr(BBA_RWP);
+ end_ptr = PtrFromPagePtr(BBA_RHBP);
+ read_ptr = PtrFromPagePtr(BBA_RRP);
descriptor = (Descriptor*)write_ptr;
write_ptr += 4;
- for (u32 i = 0, off = 4; i < mRecvBufferLength; ++i, ++off)
+ for (u32 i = 0, off = 4; i < m_recv_buffer_length; ++i, ++off)
{
- *write_ptr++ = mRecvBuffer[i];
+ *write_ptr++ = m_recv_buffer[i];
if (off == 0xff)
{
@@ -513,7 +514,7 @@ bool CEXIETHERNET::RecvHandlePacket()
}
if (write_ptr == end_ptr)
- write_ptr = ptr_from_page_ptr(BBA_BP);
+ write_ptr = PtrFromPagePtr(BBA_BP);
if (write_ptr == read_ptr)
{
@@ -529,13 +530,13 @@ bool CEXIETHERNET::RecvHandlePacket()
inc MPC instead of receiving packets
*/
status |= DESC_FO | DESC_BF;
- mBbaMem[BBA_IR] |= mBbaMem[BBA_IMR] & INT_RBF;
+ m_bba_mem.ir |= m_bba_mem.imr & INT_RBF;
break;
}
}
// Align up to next page
- if ((mRecvBufferLength + 4) % 256)
+ if ((m_recv_buffer_length + 4) % 256)
inc_rwp();
#ifdef BBA_TRACK_PAGE_PTRS
@@ -544,14 +545,14 @@ bool CEXIETHERNET::RecvHandlePacket()
#endif
// Is the current frame multicast?
- if (mRecvBuffer[0] & 0x01)
+ if (m_recv_buffer[0] & 0x01)
status |= DESC_MF;
if (status & DESC_BF)
{
- if (mBbaMem[BBA_MISC2] & MISC2_AUTORCVR)
+ if (m_bba_mem.misc2 & MISC2_AUTORCVR)
{
- *(u16*)&mBbaMem[BBA_RWP] = rwp_initial;
+ m_bba_mem.rwp = rwp_initial;
}
else
{
@@ -559,14 +560,14 @@ bool CEXIETHERNET::RecvHandlePacket()
}
}
- descriptor->set(*(u16*)&mBbaMem[BBA_RWP], 4 + mRecvBufferLength, status);
+ descriptor->set(m_bba_mem.rwp, 4 + m_recv_buffer_length, status);
- mBbaMem[BBA_LRPS] = status;
+ m_bba_mem.lrps = status;
// Raise interrupt
- if (mBbaMem[BBA_IMR] & INT_R)
+ if (m_bba_mem.imr & INT_R)
{
- mBbaMem[BBA_IR] |= INT_R;
+ m_bba_mem.ir |= INT_R;
exi_status.interrupt |= exi_status.TRANSFER;
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::NON_CPU, 0);
@@ -578,7 +579,7 @@ bool CEXIETHERNET::RecvHandlePacket()
}
wait_for_next:
- if (mBbaMem[BBA_NCRA] & NCRA_SR)
+ if (m_bba_mem.ncra & NCRA_SR)
RecvStart();
return true;
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.h
similarity index 69%
rename from Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
rename to Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.h
index 38a27bd7e0..021f91f9a7 100644
--- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetBase.h
@@ -4,17 +4,10 @@
#pragma once
-#include
-#include
-#include
-
-#ifdef _WIN32
-#include
-#endif
-
-#include "Common/Flag.h"
#include "Core/HW/EXI/EXI_Device.h"
+#include
+
class PointerWrap;
namespace ExpansionInterface
@@ -131,6 +124,7 @@ enum
BBA_NAFR_PAR3 = 0x23,
BBA_NAFR_PAR4 = 0x24,
BBA_NAFR_PAR5 = 0x25,
+
BBA_NAFR_MAR0 = 0x26,
BBA_NAFR_MAR1 = 0x27,
BBA_NAFR_MAR2 = 0x28,
@@ -157,14 +151,6 @@ enum
BBA_SI_ACTRL2 = 0x60
};
-enum
-{
- BBA_NUM_PAGES = 0x10,
- BBA_PAGE_SIZE = 0x100,
- BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE,
- BBA_TXFIFO_SIZE = 1518
-};
-
enum
{
EXI_DEVTYPE_ETHER = 0x04020200
@@ -194,13 +180,11 @@ enum RecvStatus
DESC_RERR = 0x80
};
-#define BBA_RECV_SIZE 0x800
-
-class CEXIETHERNET : public IEXIDevice
+class CEXIEthernetBase : public IEXIDevice
{
public:
- CEXIETHERNET();
- virtual ~CEXIETHERNET();
+ CEXIEthernetBase();
+
void SetCS(int cs) override;
bool IsPresent() const override;
bool IsInterruptSet() override;
@@ -210,7 +194,100 @@ public:
void DMARead(u32 addr, u32 size) override;
void DoState(PointerWrap& p) override;
-private:
+protected:
+ static constexpr std::size_t BBA_RECV_SIZE = 0x800;
+ static constexpr std::size_t BBA_NUM_PAGES = 0x10;
+ static constexpr std::size_t BBA_PAGE_SIZE = 0x100;
+ static constexpr std::size_t BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE;
+ static constexpr std::size_t BBA_TXFIFO_SIZE = 1518;
+
+ virtual bool Activate() = 0;
+ virtual bool IsActivated() const = 0;
+ virtual bool SendFrame(const u8* frame, u32 size) = 0;
+ virtual bool RecvInit() = 0;
+ virtual void RecvStart() = 0;
+ virtual void RecvStop() = 0;
+
+ inline u16 page_ptr(int const index) const
+ {
+ return ((u16)m_bba_mem.raw[index + 1] << 8) | m_bba_mem.raw[index];
+ }
+
+ inline u8* PtrFromPagePtr(int const index)
+ {
+ return &m_bba_mem.raw[page_ptr(index) << 8];
+ }
+
+ inline const u8* PtrFromPagePtr(int const index) const
+ {
+ return &m_bba_mem.raw[page_ptr(index) << 8];
+ }
+
+ bool IsMXCommand(u32 const data);
+ bool IsWriteCommand(u32 const data);
+ const char* GetRegisterName() const;
+ void MXHardReset();
+ void MXCommandHandler(u32 data, u32 size);
+ void DirectFIFOWrite(const u8* data, u32 size);
+ void SendFromDirectFIFO();
+ void SendFromPacketBuffer();
+ void SendComplete();
+ u8 HashIndex(const u8* dest_eth_addr) const;
+ bool RecvMACFilter() const;
+ void inc_rwp();
+ bool RecvHandlePacket();
+
+ union {
+ std::array raw;
+#pragma pack(push, 1)
+ struct {
+ u8 ncra; //0x00
+ u8 ncrb; //0x01
+ u16 : 16;
+ u8 ltps; //0x04
+ u8 lrps; //0x05
+ u16 : 16;
+ u8 imr; //0x08
+ u8 ir; //0x09
+ u16 bp; //0x0a
+ u16 tlbp; //0x0c
+ u16 twp; //0x0e
+ u16 iob; //0x10
+ u16 trp; //0x12
+ u16 rxintt; //0x14
+ u16 rwp; //0x16
+ u16 rrp; //0x18
+ u16 rhbp; //0x1a
+ u32 : 32;
+ std::array nafr_par; //0x20
+ std::array nafr_mar; //0x26
+ u16 : 16;
+ u8 nwayc; //0x30
+ u8 nways; //0x31
+ u8 gca; //0x32
+ u64 : 64;
+ u16 : 16;
+ u8 misc; //0x3d
+ u16 txfifocnt; //0x3e
+ u64 : 64;
+ u16 wrtxfifod; //0x48
+ u64 : 48;
+ u8 misc2; //0x50
+ u64 : 64;
+ u16 : 16;
+ u8 : 8;
+ u8 si_actrl; //0x5c
+ u8 si_status; //0x5d
+ u16 : 16;
+ u8 si_actrl2; //0x60
+ };
+#pragma pack(pop)
+ } m_bba_mem;
+ std::array m_tx_fifo;
+
+ std::array m_recv_buffer;
+ u32 m_recv_buffer_length = 0;
+
struct
{
enum
@@ -273,58 +350,5 @@ private:
word |= next_page & 0xfff;
}
};
-
- inline u16 page_ptr(int const index) const
- {
- return ((u16)mBbaMem[index + 1] << 8) | mBbaMem[index];
- }
-
- inline u8* ptr_from_page_ptr(int const index) const { return &mBbaMem[page_ptr(index) << 8]; }
- bool IsMXCommand(u32 const data);
- bool IsWriteCommand(u32 const data);
- const char* GetRegisterName() const;
- void MXHardReset();
- void MXCommandHandler(u32 data, u32 size);
- void DirectFIFOWrite(const u8* data, u32 size);
- void SendFromDirectFIFO();
- void SendFromPacketBuffer();
- void SendComplete();
- u8 HashIndex(const u8* dest_eth_addr);
- bool RecvMACFilter();
- void inc_rwp();
- bool RecvHandlePacket();
-
- std::unique_ptr mBbaMem;
- std::unique_ptr tx_fifo;
-
- // TAP interface
- static void ReadThreadHandler(CEXIETHERNET* self);
- bool Activate();
- void Deactivate();
- bool IsActivated();
- bool SendFrame(const u8* frame, u32 size);
- bool RecvInit();
- void RecvStart();
- void RecvStop();
-
- std::unique_ptr mRecvBuffer;
- u32 mRecvBufferLength = 0;
-
-#if defined(_WIN32)
- HANDLE mHAdapter = INVALID_HANDLE_VALUE;
- OVERLAPPED mReadOverlapped = {};
- OVERLAPPED mWriteOverlapped = {};
- std::vector mWriteBuffer;
- bool mWritePending = false;
-#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- int fd = -1;
-#endif
-
-#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
- defined(__OpenBSD__)
- std::thread readThread;
- Common::Flag readEnabled;
- Common::Flag readThreadShutdown;
-#endif
};
} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP.h
new file mode 100644
index 0000000000..3884ddb96e
--- /dev/null
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP.h
@@ -0,0 +1,52 @@
+// Copyright 2008 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#ifdef _WIN32
+#include
+#include
+#endif
+
+#include "Common/Flag.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetBase.h"
+
+namespace ExpansionInterface
+{
+class CEXIEthernetTAP : public CEXIEthernetBase
+{
+public:
+ ~CEXIEthernetTAP() override;
+
+protected:
+ bool Activate() override;
+ bool IsActivated() const override;
+ bool SendFrame(const u8* frame, u32 size) override;
+ bool RecvInit() override;
+ void RecvStart() override;
+ void RecvStop() override;
+
+private:
+ static void ReadThreadHandler(CEXIEthernetTAP* self);
+
+#ifdef _WIN32
+ HANDLE m_h_adapter = INVALID_HANDLE_VALUE;
+ OVERLAPPED m_read_overlapped = {};
+ OVERLAPPED m_write_overlapped = {};
+ std::vector m_write_buffer;
+ bool m_write_pending = false;
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ int m_fd = -1;
+#endif
+
+#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+ defined(__OpenBSD__)
+ std::thread m_read_thread;
+ Common::Flag m_read_enabled;
+ Common::Flag m_read_thread_shutdown;
+#endif
+};
+} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
new file mode 100644
index 0000000000..d86d64e9ae
--- /dev/null
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
@@ -0,0 +1,104 @@
+// Copyright 2008 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include
+#include
+
+#include "Common/Logging/Log.h"
+#include "Common/StringUtil.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
+
+namespace ExpansionInterface
+{
+CEXIEthernetTAP::~CEXIEthernetTAP()
+{
+ close(m_fd);
+
+ m_read_enabled.Clear();
+ m_read_thread_shutdown.Set();
+ if (m_read_thread.joinable())
+ m_read_thread.join();
+}
+
+bool CEXIEthernetTAP::Activate()
+{
+ if (IsActivated())
+ return true;
+
+ // Assumes TunTap OS X is installed, and /dev/tun0 is not in use
+ // and readable / writable by the logged-in user
+
+ if ((m_fd = open("/dev/tap0", O_RDWR)) < 0)
+ {
+ ERROR_LOG(SP1, "Couldn't open /dev/tap0, unable to init BBA");
+ return false;
+ }
+
+ INFO_LOG(SP1, "BBA initialized.");
+ return RecvInit();
+}
+
+bool CEXIEthernetTAP::IsActivated() const
+{
+ return m_fd != -1;
+}
+
+bool CEXIEthernetTAP::SendFrame(const u8* frame, u32 size)
+{
+ int writtenBytes = write(m_fd, frame, size);
+ if ((u32)writtenBytes != size)
+ {
+ ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes);
+ return false;
+ }
+ else
+ {
+ SendComplete();
+ return true;
+ }
+}
+
+void CEXIEthernetTAP::ReadThreadHandler(CEXIEthernetTAP* self)
+{
+ while (!self->m_read_thread_shutdown.IsSet())
+ {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(self->m_fd, &rfds);
+
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 50000;
+ if (select(self->m_fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0)
+ continue;
+
+ int readBytes = read(self->m_fd, &self->m_recv_buffer, BBA_RECV_SIZE);
+ if (readBytes < 0)
+ {
+ ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes);
+ }
+ else if (self->m_read_enabled.IsSet())
+ {
+ self->m_recv_buffer_length = readBytes;
+ self->RecvHandlePacket();
+ }
+ }
+}
+
+bool CEXIEthernetTAP::RecvInit()
+{
+ m_read_thread = std::thread(ReadThreadHandler, this);
+ return true;
+}
+
+void CEXIEthernetTAP::RecvStart()
+{
+ m_read_enabled.Set();
+}
+
+void CEXIEthernetTAP::RecvStop()
+{
+ m_read_enabled.Clear();
+}
+} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Unix.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Unix.cpp
similarity index 57%
rename from Source/Core/Core/HW/EXI/BBA-TAP/TAP_Unix.cpp
rename to Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Unix.cpp
index 05505af9db..a404f7a3a0 100644
--- a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Unix.cpp
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Unix.cpp
@@ -11,7 +11,7 @@
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Core/HW/EXI/EXI_Device.h"
-#include "Core/HW/EXI/EXI_DeviceEthernet.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
#ifdef __linux__
#include
@@ -25,10 +25,24 @@
namespace ExpansionInterface
{
-#define NOTIMPLEMENTED(Name) \
- NOTICE_LOG(SP1, "CEXIETHERNET::%s not implemented for your UNIX", Name);
+#define NOTIMPLEMENTED \
+ NOTICE_LOG(SP1, "%s not implemented for your UNIX", __PRETTY_FUNCTION__);
-bool CEXIETHERNET::Activate()
+CEXIEthernetTAP::~CEXIEthernetTAP()
+{
+#ifdef __linux__
+ close(m_fd);
+
+ m_read_enabled.Clear();
+ m_read_thread_shutdown.Set();
+ if (m_read_thread.joinable())
+ m_read_thread.join();
+#else
+ NOTIMPLEMENTED;
+#endif
+}
+
+bool CEXIEthernetTAP::Activate()
{
#ifdef __linux__
if (IsActivated())
@@ -37,7 +51,7 @@ bool CEXIETHERNET::Activate()
// Assumes that there is a TAP device named "Dolphin" preconfigured for
// bridge/NAT/whatever the user wants it configured.
- if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ if ((m_fd = open("/dev/net/tun", O_RDWR)) < 0)
{
ERROR_LOG(SP1, "Couldn't open /dev/net/tun, unable to init BBA");
return false;
@@ -53,12 +67,12 @@ bool CEXIETHERNET::Activate()
strncpy(ifr.ifr_name, StringFromFormat("Dolphin%d", i).c_str(), IFNAMSIZ);
int err;
- if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0)
+ if ((err = ioctl(m_fd, TUNSETIFF, (void*)&ifr)) < 0)
{
if (i == (MAX_INTERFACES - 1))
{
- close(fd);
- fd = -1;
+ close(m_fd);
+ m_fd = -1;
ERROR_LOG(SP1, "TUNSETIFF failed: Interface=%s err=%d", ifr.ifr_name, err);
return false;
}
@@ -68,46 +82,29 @@ bool CEXIETHERNET::Activate()
break;
}
}
- ioctl(fd, TUNSETNOCSUM, 1);
+ ioctl(m_fd, TUNSETNOCSUM, 1);
INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name);
return RecvInit();
#else
- NOTIMPLEMENTED("Activate");
+ NOTIMPLEMENTED;
return false;
#endif
}
-void CEXIETHERNET::Deactivate()
+bool CEXIEthernetTAP::IsActivated() const
{
#ifdef __linux__
- close(fd);
- fd = -1;
-
- readEnabled.Clear();
- readThreadShutdown.Set();
- if (readThread.joinable())
- readThread.join();
-#else
- NOTIMPLEMENTED("Deactivate");
-#endif
-}
-
-bool CEXIETHERNET::IsActivated()
-{
-#ifdef __linux__
- return fd != -1 ? true : false;
+ return m_fd != -1;
#else
return false;
#endif
}
-bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
+bool CEXIEthernetTAP::SendFrame(const u8* frame, u32 size)
{
#ifdef __linux__
- DEBUG_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str());
-
- int writtenBytes = write(fd, frame, size);
+ int writtenBytes = write(m_fd, frame, size);
if ((u32)writtenBytes != size)
{
ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes);
@@ -119,68 +116,66 @@ bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
return true;
}
#else
- NOTIMPLEMENTED("SendFrame");
+ NOTIMPLEMENTED;
return false;
#endif
}
-#ifdef __linux__
-void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
+bool CEXIEthernetTAP::RecvInit()
{
- while (!self->readThreadShutdown.IsSet())
+#ifdef __linux__
+ m_read_thread = std::thread(ReadThreadHandler, this);
+ return true;
+#else
+ NOTIMPLEMENTED;
+ return false;
+#endif
+}
+
+void CEXIEthernetTAP::RecvStart()
+{
+#ifdef __linux__
+ m_read_enabled.Set();
+#else
+ NOTIMPLEMENTED;
+#endif
+}
+
+void CEXIEthernetTAP::RecvStop()
+{
+#ifdef __linux__
+ m_read_enabled.Clear();
+#else
+ NOTIMPLEMENTED("RecvStop");
+#endif
+}
+
+#ifdef __linux__
+void CEXIEthernetTAP::ReadThreadHandler(CEXIEthernetTAP* self)
+{
+ while (!self->m_read_thread_shutdown.IsSet())
{
fd_set rfds;
FD_ZERO(&rfds);
- FD_SET(self->fd, &rfds);
+ FD_SET(self->m_fd, &rfds);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000;
- if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0)
+ if (select(self->m_fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0)
continue;
- int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE);
+ int readBytes = read(self->m_fd, &self->m_recv_buffer, BBA_RECV_SIZE);
if (readBytes < 0)
{
ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes);
}
- else if (self->readEnabled.IsSet())
+ else if (self->m_read_enabled.IsSet())
{
- DEBUG_LOG(SP1, "Read data: %s",
- ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str());
- self->mRecvBufferLength = readBytes;
+ self->m_recv_buffer_length = readBytes;
self->RecvHandlePacket();
}
}
}
#endif
-
-bool CEXIETHERNET::RecvInit()
-{
-#ifdef __linux__
- readThread = std::thread(ReadThreadHandler, this);
- return true;
-#else
- NOTIMPLEMENTED("RecvInit");
- return false;
-#endif
-}
-
-void CEXIETHERNET::RecvStart()
-{
-#ifdef __linux__
- readEnabled.Set();
-#else
- NOTIMPLEMENTED("RecvStart");
-#endif
-}
-
-void CEXIETHERNET::RecvStop()
-{
-#ifdef __linux__
- readEnabled.Clear();
-#else
- NOTIMPLEMENTED("RecvStop");
-#endif
-}
} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Win32.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Win32.cpp
similarity index 75%
rename from Source/Core/Core/HW/EXI/BBA-TAP/TAP_Win32.cpp
rename to Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Win32.cpp
index 3e8b4d5442..1a71bf387a 100644
--- a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Win32.cpp
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Win32.cpp
@@ -2,13 +2,12 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-#include "Core/HW/EXI/BBA-TAP/TAP_Win32.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetTAP_Win32.h"
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
-#include "Core/HW/EXI/EXI_Device.h"
-#include "Core/HW/EXI/EXI_DeviceEthernet.h"
+#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
namespace Win32TAPHelper
{
@@ -167,7 +166,32 @@ bool OpenTAP(HANDLE& adapter, const std::basic_string& device_guid)
namespace ExpansionInterface
{
-bool CEXIETHERNET::Activate()
+CEXIEthernetTAP::~CEXIEthernetTAP()
+{
+ if (!IsActivated())
+ return;
+
+ // Signal read thread to exit.
+ m_read_enabled.Clear();
+ m_read_thread_shutdown.Set();
+
+ // Cancel any outstanding requests from both this thread (writes), and the read thread.
+ CancelIoEx(m_h_adapter, nullptr);
+
+ // Wait for read thread to exit.
+ if (m_read_thread.joinable())
+ m_read_thread.join();
+
+ // Clean-up handles
+ CloseHandle(m_read_overlapped.hEvent);
+ CloseHandle(m_write_overlapped.hEvent);
+ CloseHandle(m_h_adapter);
+ m_h_adapter = INVALID_HANDLE_VALUE;
+ memset(&m_read_overlapped, 0, sizeof(m_read_overlapped));
+ memset(&m_write_overlapped, 0, sizeof(m_write_overlapped));
+}
+
+bool CEXIEthernetTAP::Activate()
{
if (IsActivated())
return true;
@@ -183,13 +207,13 @@ bool CEXIETHERNET::Activate()
for (size_t i = 0; i < device_guids.size(); i++)
{
- if (Win32TAPHelper::OpenTAP(mHAdapter, device_guids.at(i)))
+ if (Win32TAPHelper::OpenTAP(m_h_adapter, device_guids.at(i)))
{
INFO_LOG(SP1, "OPENED %s", device_guids.at(i).c_str());
break;
}
}
- if (mHAdapter == INVALID_HANDLE_VALUE)
+ if (m_h_adapter == INVALID_HANDLE_VALUE)
{
PanicAlert("Failed to open any TAP");
return false;
@@ -197,7 +221,7 @@ bool CEXIETHERNET::Activate()
/* get driver version info */
ULONG info[3];
- if (DeviceIoControl(mHAdapter, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info),
+ if (DeviceIoControl(m_h_adapter, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info),
&len, nullptr))
{
INFO_LOG(SP1, "TAP-Win32 Driver Version %d.%d %s", info[0], info[1], info[2] ? "(DEBUG)" : "");
@@ -215,7 +239,7 @@ bool CEXIETHERNET::Activate()
/* set driver media status to 'connected' */
ULONG status = TRUE;
- if (!DeviceIoControl(mHAdapter, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status,
+ if (!DeviceIoControl(m_h_adapter, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status,
sizeof(status), &len, nullptr))
{
ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a"
@@ -224,57 +248,32 @@ bool CEXIETHERNET::Activate()
}
/* initialize read/write events */
- mReadOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- mWriteOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- if (mReadOverlapped.hEvent == nullptr || mWriteOverlapped.hEvent == nullptr)
+ m_read_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ m_write_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ if (m_read_overlapped.hEvent == nullptr || m_write_overlapped.hEvent == nullptr)
return false;
- mWriteBuffer.reserve(1518);
+ m_write_buffer.reserve(1518);
return RecvInit();
}
-void CEXIETHERNET::Deactivate()
+bool CEXIEthernetTAP::IsActivated() const
{
- if (!IsActivated())
- return;
-
- // Signal read thread to exit.
- readEnabled.Clear();
- readThreadShutdown.Set();
-
- // Cancel any outstanding requests from both this thread (writes), and the read thread.
- CancelIoEx(mHAdapter, nullptr);
-
- // Wait for read thread to exit.
- if (readThread.joinable())
- readThread.join();
-
- // Clean-up handles
- CloseHandle(mReadOverlapped.hEvent);
- CloseHandle(mWriteOverlapped.hEvent);
- CloseHandle(mHAdapter);
- mHAdapter = INVALID_HANDLE_VALUE;
- memset(&mReadOverlapped, 0, sizeof(mReadOverlapped));
- memset(&mWriteOverlapped, 0, sizeof(mWriteOverlapped));
+ return m_h_adapter != INVALID_HANDLE_VALUE;
}
-bool CEXIETHERNET::IsActivated()
+void CEXIEthernetTAP::ReadThreadHandler(CEXIEthernetTAP* self)
{
- return mHAdapter != INVALID_HANDLE_VALUE;
-}
-
-void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
-{
- while (!self->readThreadShutdown.IsSet())
+ while (!self->m_read_thread_shutdown.IsSet())
{
DWORD transferred;
// Read from TAP into internal buffer.
- if (ReadFile(self->mHAdapter, self->mRecvBuffer.get(), BBA_RECV_SIZE, &transferred,
- &self->mReadOverlapped))
+ if (ReadFile(self->m_h_adapter, &self->m_recv_buffer, BBA_RECV_SIZE, &transferred,
+ &self->m_read_overlapped))
{
// Returning immediately is not likely to happen, but if so, reset the event state manually.
- ResetEvent(self->mReadOverlapped.hEvent);
+ ResetEvent(self->m_read_overlapped.hEvent);
}
else
{
@@ -286,7 +285,7 @@ void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
}
// Block until the read completes.
- if (!GetOverlappedResult(self->mHAdapter, &self->mReadOverlapped, &transferred, TRUE))
+ if (!GetOverlappedResult(self->m_h_adapter, &self->m_read_overlapped, &transferred, TRUE))
{
// If CancelIO was called, we should exit (the flag will be set).
if (GetLastError() == ERROR_OPERATION_ABORTED)
@@ -299,38 +298,34 @@ void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
}
// Copy to BBA buffer, and fire interrupt if enabled.
- DEBUG_LOG(SP1, "Received %u bytes:\n %s", transferred,
- ArrayToString(self->mRecvBuffer.get(), transferred, 0x10).c_str());
- if (self->readEnabled.IsSet())
+ if (self->m_read_enabled.IsSet())
{
- self->mRecvBufferLength = transferred;
+ self->m_recv_buffer_length = transferred;
self->RecvHandlePacket();
}
}
}
-bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
+bool CEXIEthernetTAP::SendFrame(const u8* frame, u32 size)
{
- DEBUG_LOG(SP1, "SendFrame %u bytes:\n%s", size, ArrayToString(frame, size, 0x10).c_str());
-
// Check for a background write. We can't issue another one until this one has completed.
DWORD transferred;
- if (mWritePending)
+ if (m_write_pending)
{
// Wait for previous write to complete.
- if (!GetOverlappedResult(mHAdapter, &mWriteOverlapped, &transferred, TRUE))
+ if (!GetOverlappedResult(m_h_adapter, &m_write_overlapped, &transferred, TRUE))
ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError());
}
// Copy to write buffer.
- mWriteBuffer.assign(frame, frame + size);
- mWritePending = true;
+ m_write_buffer.assign(frame, frame + size);
+ m_write_pending = true;
// Queue async write.
- if (WriteFile(mHAdapter, mWriteBuffer.data(), size, &transferred, &mWriteOverlapped))
+ if (WriteFile(m_h_adapter, m_write_buffer.data(), size, &transferred, &m_write_overlapped))
{
// Returning immediately is not likely to happen, but if so, reset the event state manually.
- ResetEvent(mWriteOverlapped.hEvent);
+ ResetEvent(m_write_overlapped.hEvent);
}
else
{
@@ -338,8 +333,8 @@ bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
if (GetLastError() != ERROR_IO_PENDING)
{
ERROR_LOG(SP1, "WriteFile failed (err=0x%X)", GetLastError());
- ResetEvent(mWriteOverlapped.hEvent);
- mWritePending = false;
+ ResetEvent(m_write_overlapped.hEvent);
+ m_write_pending = false;
return false;
}
}
@@ -349,19 +344,19 @@ bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
return true;
}
-bool CEXIETHERNET::RecvInit()
+bool CEXIEthernetTAP::RecvInit()
{
- readThread = std::thread(ReadThreadHandler, this);
+ m_read_thread = std::thread(ReadThreadHandler, this);
return true;
}
-void CEXIETHERNET::RecvStart()
+void CEXIEthernetTAP::RecvStart()
{
- readEnabled.Set();
+ m_read_enabled.Set();
}
-void CEXIETHERNET::RecvStop()
+void CEXIEthernetTAP::RecvStop()
{
- readEnabled.Clear();
+ m_read_enabled.Clear();
}
} // namespace ExpansionInterface
diff --git a/Source/Core/Core/HW/EXI/BBA-TAP/TAP_Win32.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernetTap_Win32.h
similarity index 100%
rename from Source/Core/Core/HW/EXI/BBA-TAP/TAP_Win32.h
rename to Source/Core/Core/HW/EXI/EXI_DeviceEthernetTap_Win32.h
diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt
index 1bf9844ff6..208661dd17 100644
--- a/Source/Core/DolphinQt/CMakeLists.txt
+++ b/Source/Core/DolphinQt/CMakeLists.txt
@@ -48,6 +48,8 @@ add_executable(dolphin-emu
Config/ARCodeWidget.cpp
Config/ARCodeWidget.h
Config/CheatCodeEditor.cpp
+ Config/ARCodeWidget.cpp
+ Config/BBAConfigWidget.cpp
Config/CheatCodeEditor.h
Config/CheatWarningWidget.cpp
Config/CheatWarningWidget.h
diff --git a/Source/Core/DolphinQt/Config/BBAConfigWidget.cpp b/Source/Core/DolphinQt/Config/BBAConfigWidget.cpp
new file mode 100644
index 0000000000..a3ff885f30
--- /dev/null
+++ b/Source/Core/DolphinQt/Config/BBAConfigWidget.cpp
@@ -0,0 +1,94 @@
+// Copyright 2019 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "DolphinQt/Config/BBAConfigWidget.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Common/Network.h"
+
+BBAConfigWidget::BBAConfigWidget(QWidget* parent) : QDialog(parent)
+{
+ setWindowTitle(tr("Broadband Adapter Configuration"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ auto* vbox_layout = new QVBoxLayout(this);
+
+ {
+ auto* form_layout = new QFormLayout;
+
+ {
+ auto* hbox_layout = new QHBoxLayout;
+
+ m_mac_addr = new QLineEdit(this);
+ m_mac_addr->setPlaceholderText(tr("Leave empty for random"));
+ connect(m_mac_addr, &QLineEdit::textChanged, this, &BBAConfigWidget::TextChanged);
+ hbox_layout->addWidget(m_mac_addr);
+
+ {
+ auto* button = new QToolButton(this);
+ button->setText(tr("Randomize"));
+ connect(button, &QAbstractButton::pressed, this, &BBAConfigWidget::GenerateMac);
+ hbox_layout->addWidget(button);
+ }
+
+ form_layout->addRow(tr("MAC address:"), hbox_layout);
+ }
+
+ vbox_layout->addLayout(form_layout, 1);
+ }
+
+ {
+ auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close, this);
+ connect(button_box, &QDialogButtonBox::accepted, this, &BBAConfigWidget::Submit);
+ connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ vbox_layout->addWidget(button_box, 1);
+ }
+
+ setLayout(vbox_layout);
+}
+
+QString BBAConfigWidget::MacAddr() const
+{
+ return m_mac_addr->text();
+}
+
+void BBAConfigWidget::SetMacAddr(const QString& mac_addr)
+{
+ m_mac_addr->setText(mac_addr);
+}
+
+void BBAConfigWidget::Submit()
+{
+ if (!MacAddr().isEmpty() && !Common::StringToMacAddress(MacAddr().toStdString()))
+ {
+ QMessageBox::warning(this, tr("Invalid MAC address!"), tr("Invalid MAC address!"));
+ return;
+ }
+
+ accept();
+}
+
+void BBAConfigWidget::GenerateMac()
+{
+ m_mac_addr->setText(QString::fromStdString(
+ Common::MacAddressToString(Common::GenerateMacAddress(Common::MACConsumer::BBA))));
+}
+
+void BBAConfigWidget::TextChanged(const QString& text)
+{
+ QString inputMask;
+ if (!text.isEmpty() && text != QStringLiteral(":::::"))
+ inputMask = QStringLiteral("HH:HH:HH:HH:HH:HH;_");
+ if (m_mac_addr->inputMask() != inputMask)
+ m_mac_addr->setInputMask(inputMask);
+}
diff --git a/Source/Core/DolphinQt/Config/BBAConfigWidget.h b/Source/Core/DolphinQt/Config/BBAConfigWidget.h
new file mode 100644
index 0000000000..26efc6a2e1
--- /dev/null
+++ b/Source/Core/DolphinQt/Config/BBAConfigWidget.h
@@ -0,0 +1,29 @@
+// Copyright 2019 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+class QLineEdit;
+class QSpinBox;
+
+class BBAConfigWidget : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit BBAConfigWidget(QWidget* parent = nullptr);
+
+ QString MacAddr() const;
+ void SetMacAddr(const QString& mac_addr);
+
+private slots:
+ void Submit();
+ void GenerateMac();
+ void TextChanged(const QString& text);
+
+private:
+ QLineEdit* m_mac_addr;
+};
diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj
index 2deb34cffc..7778a351b2 100644
--- a/Source/Core/DolphinQt/DolphinQt.vcxproj
+++ b/Source/Core/DolphinQt/DolphinQt.vcxproj
@@ -60,6 +60,7 @@
+
@@ -178,6 +179,7 @@
+
@@ -288,6 +290,7 @@
+
diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp
index b0cfab9999..8a5f20aa2d 100644
--- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp
+++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp
@@ -27,6 +27,7 @@
#include "Core/HW/EXI/EXI.h"
#include "Core/HW/GCMemcard/GCMemcard.h"
+#include "DolphinQt/Config/BBAConfigWidget.h"
#include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "DolphinQt/GCMemcardManager.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h"
@@ -103,7 +104,7 @@ void GameCubePane::CreateWidgets()
for (const auto& entry :
{std::make_pair(tr(""), ExpansionInterface::EXIDEVICE_NONE),
std::make_pair(tr("Dummy"), ExpansionInterface::EXIDEVICE_DUMMY),
- std::make_pair(tr("Broadband Adapter"), ExpansionInterface::EXIDEVICE_ETH)})
+ std::make_pair(tr("Broadband Adapter (TAP)", "virtual network device"), ExpansionInterface::EXIDEVICE_ETH_TAP)})
{
m_slot_combos[2]->addItem(entry.first, entry.second);
}
@@ -158,7 +159,7 @@ void GameCubePane::UpdateButton(int slot)
value == ExpansionInterface::EXIDEVICE_AGP || value == ExpansionInterface::EXIDEVICE_MIC);
break;
case SLOT_SP1_INDEX:
- has_config = (value == ExpansionInterface::EXIDEVICE_ETH);
+ has_config = (value == ExpansionInterface::EXIDEVICE_ETH_TAP);
break;
}
@@ -170,7 +171,9 @@ void GameCubePane::OnConfigPressed(int slot)
QString filter;
bool memcard = false;
- switch (m_slot_combos[slot]->currentData().toInt())
+ const auto current_data = m_slot_combos[slot]->currentData().toInt();
+
+ switch (current_data)
{
case ExpansionInterface::EXIDEVICE_MEMORYCARD:
filter = tr("GameCube Memory Cards (*.raw *.gcp)");
@@ -182,14 +185,14 @@ void GameCubePane::OnConfigPressed(int slot)
case ExpansionInterface::EXIDEVICE_MIC:
MappingWindow(this, MappingWindow::Type::MAPPING_GC_MICROPHONE, slot).exec();
return;
- case ExpansionInterface::EXIDEVICE_ETH:
+ case ExpansionInterface::EXIDEVICE_ETH_TAP:
{
- bool ok;
- const auto new_mac = QInputDialog::getText(
- this, tr("Broadband Adapter MAC address"), tr("Enter new Broadband Adapter MAC address:"),
- QLineEdit::Normal, QString::fromStdString(SConfig::GetInstance().m_bba_mac), &ok);
- if (ok)
- SConfig::GetInstance().m_bba_mac = new_mac.toStdString();
+ BBAConfigWidget dialog(this);
+ dialog.SetMacAddr(QString::fromStdString(SConfig::GetInstance().m_bba_mac));
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ SConfig::GetInstance().m_bba_mac = dialog.MacAddr().toStdString();
+ }
return;
}
default:
@@ -198,7 +201,7 @@ void GameCubePane::OnConfigPressed(int slot)
QString filename = QFileDialog::getSaveFileName(
this, tr("Choose a file to open"), QString::fromStdString(File::GetUserPath(D_GCUSER_IDX)),
- filter, 0, QFileDialog::DontConfirmOverwrite);
+ filter, nullptr, QFileDialog::DontConfirmOverwrite);
if (filename.isEmpty())
return;