forked from dolphin-emu/dolphin
BBA refactorings
This commit is contained in:
@@ -203,8 +203,9 @@ add_library(core
|
|||||||
HW/EXI/EXI_DeviceAGP.h
|
HW/EXI/EXI_DeviceAGP.h
|
||||||
HW/EXI/EXI_DeviceDummy.cpp
|
HW/EXI/EXI_DeviceDummy.cpp
|
||||||
HW/EXI/EXI_DeviceDummy.h
|
HW/EXI/EXI_DeviceDummy.h
|
||||||
HW/EXI/EXI_DeviceEthernet.cpp
|
HW/EXI/EXI_DeviceEthernetBase.cpp
|
||||||
HW/EXI/EXI_DeviceEthernet.h
|
HW/EXI/EXI_DeviceEthernetBase.h
|
||||||
|
HW/EXI/EXI_DeviceEthernetTAP.h
|
||||||
HW/EXI/EXI_DeviceGecko.cpp
|
HW/EXI/EXI_DeviceGecko.cpp
|
||||||
HW/EXI/EXI_DeviceGecko.h
|
HW/EXI/EXI_DeviceGecko.h
|
||||||
HW/EXI/EXI_DeviceIPL.cpp
|
HW/EXI/EXI_DeviceIPL.cpp
|
||||||
@@ -589,8 +590,8 @@ endif()
|
|||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
HW/EXI/BBA-TAP/TAP_Win32.cpp
|
HW/EXI/EXI_DeviceEthernetTap_Win32.cpp
|
||||||
HW/EXI/BBA-TAP/TAP_Win32.h
|
HW/EXI/EXI_DeviceEthernetTap_Win32.h
|
||||||
HW/WiimoteReal/IOWin.cpp
|
HW/WiimoteReal/IOWin.cpp
|
||||||
HW/WiimoteReal/IOWin.h
|
HW/WiimoteReal/IOWin.h
|
||||||
)
|
)
|
||||||
@@ -603,7 +604,7 @@ if(WIN32)
|
|||||||
target_compile_definitions(core PRIVATE "-D_WINSOCK_DEPRECATED_NO_WARNINGS")
|
target_compile_definitions(core PRIVATE "-D_WINSOCK_DEPRECATED_NO_WARNINGS")
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
HW/EXI/BBA-TAP/TAP_Apple.cpp
|
HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
|
||||||
HW/WiimoteReal/IOdarwin.h
|
HW/WiimoteReal/IOdarwin.h
|
||||||
HW/WiimoteReal/IOdarwin_private.h
|
HW/WiimoteReal/IOdarwin_private.h
|
||||||
HW/WiimoteReal/IOdarwin.mm
|
HW/WiimoteReal/IOdarwin.mm
|
||||||
@@ -611,7 +612,7 @@ elseif(APPLE)
|
|||||||
target_link_libraries(core PUBLIC ${IOB_LIBRARY})
|
target_link_libraries(core PUBLIC ${IOB_LIBRARY})
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
HW/EXI/BBA-TAP/TAP_Unix.cpp
|
HW/EXI/EXI_DeviceEthernetTAP_Unix.cpp
|
||||||
)
|
)
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
|
@@ -132,14 +132,14 @@
|
|||||||
<ClCompile Include="HW\DVD\DVDMath.cpp" />
|
<ClCompile Include="HW\DVD\DVDMath.cpp" />
|
||||||
<ClCompile Include="HW\DVD\DVDThread.cpp" />
|
<ClCompile Include="HW\DVD\DVDThread.cpp" />
|
||||||
<ClCompile Include="HW\DVD\FileMonitor.cpp" />
|
<ClCompile Include="HW\DVD\FileMonitor.cpp" />
|
||||||
<ClCompile Include="HW\EXI\BBA-TAP\TAP_Win32.cpp" />
|
|
||||||
<ClCompile Include="HW\EXI\EXI.cpp" />
|
<ClCompile Include="HW\EXI\EXI.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_Channel.cpp" />
|
<ClCompile Include="HW\EXI\EXI_Channel.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_Device.cpp" />
|
<ClCompile Include="HW\EXI\EXI_Device.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceAD16.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceAD16.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceAGP.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceAGP.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceDummy.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceDummy.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceEthernet.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceEthernetBase.cpp" />
|
||||||
|
<ClCompile Include="HW\EXI\EXI_DeviceEthernetTAP_Win32.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceGecko.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceGecko.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceIPL.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceIPL.cpp" />
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceMemoryCard.cpp" />
|
<ClCompile Include="HW\EXI\EXI_DeviceMemoryCard.cpp" />
|
||||||
@@ -404,14 +404,15 @@
|
|||||||
<ClInclude Include="HW\DVD\DVDMath.h" />
|
<ClInclude Include="HW\DVD\DVDMath.h" />
|
||||||
<ClInclude Include="HW\DVD\DVDThread.h" />
|
<ClInclude Include="HW\DVD\DVDThread.h" />
|
||||||
<ClInclude Include="HW\DVD\FileMonitor.h" />
|
<ClInclude Include="HW\DVD\FileMonitor.h" />
|
||||||
<ClInclude Include="HW\EXI\BBA-TAP\TAP_Win32.h" />
|
|
||||||
<ClInclude Include="HW\EXI\EXI.h" />
|
<ClInclude Include="HW\EXI\EXI.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_Channel.h" />
|
<ClInclude Include="HW\EXI\EXI_Channel.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_Device.h" />
|
<ClInclude Include="HW\EXI\EXI_Device.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceAD16.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceAD16.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceAGP.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceAGP.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceDummy.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceDummy.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceEthernet.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetBase.h" />
|
||||||
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetTAP.h" />
|
||||||
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetTAP_Win32.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceGecko.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceGecko.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceIPL.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceIPL.h" />
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceMemoryCard.h" />
|
<ClInclude Include="HW\EXI\EXI_DeviceMemoryCard.h" />
|
||||||
|
@@ -442,7 +442,13 @@
|
|||||||
<ClCompile Include="HW\EXI\EXI_DeviceDummy.cpp">
|
<ClCompile Include="HW\EXI\EXI_DeviceDummy.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceEthernet.cpp">
|
<ClCompile Include="HW\EXI\EXI_DeviceEthernetBase.cpp">
|
||||||
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="HW\EXI\EXI_DeviceEthernetTAP.cpp">
|
||||||
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="HW\EXI\EXI_DeviceEthernetTAP_Win32.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\EXI\EXI_DeviceGecko.cpp">
|
<ClCompile Include="HW\EXI\EXI_DeviceGecko.cpp">
|
||||||
@@ -457,9 +463,6 @@
|
|||||||
<ClCompile Include="HW\EXI\EXI_DeviceMic.cpp">
|
<ClCompile Include="HW\EXI\EXI_DeviceMic.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\EXI\BBA-TAP\TAP_Win32.cpp">
|
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="HW\Sram.cpp">
|
<ClCompile Include="HW\Sram.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1157,7 +1160,13 @@
|
|||||||
<ClInclude Include="HW\EXI\EXI_DeviceDummy.h">
|
<ClInclude Include="HW\EXI\EXI_DeviceDummy.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceEthernet.h">
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetBase.h">
|
||||||
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetTAP.h">
|
||||||
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="HW\EXI\EXI_DeviceEthernetTAP_Win32.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\EXI\EXI_DeviceGecko.h">
|
<ClInclude Include="HW\EXI\EXI_DeviceGecko.h">
|
||||||
@@ -1172,9 +1181,6 @@
|
|||||||
<ClInclude Include="HW\EXI\EXI_DeviceMic.h">
|
<ClInclude Include="HW\EXI\EXI_DeviceMic.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\EXI\BBA-TAP\TAP_Win32.h">
|
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="HW\Sram.h">
|
<ClInclude Include="HW\Sram.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -1,110 +0,0 @@
|
|||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#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
|
|
@@ -10,7 +10,7 @@
|
|||||||
#include "Core/HW/EXI/EXI_DeviceAD16.h"
|
#include "Core/HW/EXI/EXI_DeviceAD16.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceAGP.h"
|
#include "Core/HW/EXI/EXI_DeviceAGP.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceDummy.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_DeviceGecko.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceMemoryCard.h"
|
#include "Core/HW/EXI/EXI_DeviceMemoryCard.h"
|
||||||
@@ -131,8 +131,8 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(const TEXIDevices device_type, cons
|
|||||||
result = std::make_unique<CEXIMic>(channel_num);
|
result = std::make_unique<CEXIMic>(channel_num);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_ETH:
|
case EXIDEVICE_ETH_TAP:
|
||||||
result = std::make_unique<CEXIETHERNET>();
|
result = std::make_unique<CEXIEthernetTAP>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXIDEVICE_GECKO:
|
case EXIDEVICE_GECKO:
|
||||||
|
@@ -18,7 +18,7 @@ enum TEXIDevices : int
|
|||||||
EXIDEVICE_MASKROM,
|
EXIDEVICE_MASKROM,
|
||||||
EXIDEVICE_AD16,
|
EXIDEVICE_AD16,
|
||||||
EXIDEVICE_MIC,
|
EXIDEVICE_MIC,
|
||||||
EXIDEVICE_ETH,
|
EXIDEVICE_ETH_TAP,
|
||||||
// Was used for Triforce in the past, but the implementation is no longer in Dolphin.
|
// 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.
|
// It's kept here so that values below will stay constant.
|
||||||
EXIDEVICE_AM_BASEBOARD,
|
EXIDEVICE_AM_BASEBOARD,
|
||||||
|
@@ -2,11 +2,7 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
|
#include "Core/HW/EXI/EXI_DeviceEthernetBase.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
@@ -22,40 +18,42 @@ namespace ExpansionInterface
|
|||||||
// XXX: The BBA stores multi-byte elements as little endian.
|
// XXX: The BBA stores multi-byte elements as little endian.
|
||||||
// Multiple parts of this implementation depend on Dolphin
|
// Multiple parts of this implementation depend on Dolphin
|
||||||
// being compiled for a little endian host.
|
// being compiled for a little endian host.
|
||||||
|
CEXIEthernetBase::CEXIEthernetBase()
|
||||||
CEXIETHERNET::CEXIETHERNET()
|
|
||||||
{
|
{
|
||||||
tx_fifo = std::make_unique<u8[]>(BBA_TXFIFO_SIZE);
|
|
||||||
mBbaMem = std::make_unique<u8[]>(BBA_MEM_SIZE);
|
|
||||||
mRecvBuffer = std::make_unique<u8[]>(BBA_RECV_SIZE);
|
|
||||||
|
|
||||||
MXHardReset();
|
MXHardReset();
|
||||||
|
|
||||||
// Parse MAC address from config, and generate a new one if it doesn't
|
// Parse MAC address from config, and generate a new one if it doesn't
|
||||||
// exist or can't be parsed.
|
// exist or can't be parsed.
|
||||||
std::string& mac_addr_setting = SConfig::GetInstance().m_bba_mac;
|
const std::string& mac_addr_setting = SConfig::GetInstance().m_bba_mac;
|
||||||
std::optional<Common::MACAddress> mac_addr = Common::StringToMacAddress(mac_addr_setting);
|
Common::MACAddress mac_addr;
|
||||||
|
|
||||||
if (!mac_addr)
|
if (mac_addr_setting.empty())
|
||||||
{
|
{
|
||||||
mac_addr = Common::GenerateMacAddress(Common::MACConsumer::BBA);
|
mac_addr = Common::GenerateMacAddress(Common::MACConsumer::BBA);
|
||||||
mac_addr_setting = Common::MacAddressToString(mac_addr.value());
|
}
|
||||||
SConfig::GetInstance().SaveSettings();
|
else
|
||||||
|
{
|
||||||
|
std::optional<Common::MACAddress> 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(&m_bba_mem.nafr_par, mac_addr.data(), mac_addr.size());
|
||||||
memcpy(&mBbaMem[BBA_NAFR_PAR0], mac.data(), mac.size());
|
|
||||||
|
|
||||||
// HACK: .. fully established 100BASE-T link
|
// 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()
|
void CEXIEthernetBase::SetCS(int cs)
|
||||||
{
|
|
||||||
Deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEXIETHERNET::SetCS(int cs)
|
|
||||||
{
|
{
|
||||||
if (cs)
|
if (cs)
|
||||||
{
|
{
|
||||||
@@ -64,17 +62,17 @@ void CEXIETHERNET::SetCS(int cs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIETHERNET::IsPresent() const
|
bool CEXIEthernetBase::IsPresent() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIETHERNET::IsInterruptSet()
|
bool CEXIEthernetBase::IsInterruptSet()
|
||||||
{
|
{
|
||||||
return !!(exi_status.interrupt & exi_status.interrupt_mask);
|
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;
|
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;
|
u32 ret = 0;
|
||||||
|
|
||||||
@@ -155,7 +153,7 @@ u32 CEXIETHERNET::ImmRead(u32 size)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = size - 1; i >= 0; i--)
|
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);
|
DEBUG_LOG(SP1, "imm r%i: %0*x", size, size * 2, ret);
|
||||||
@@ -165,7 +163,7 @@ u32 CEXIETHERNET::ImmRead(u32 size)
|
|||||||
return ret;
|
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);
|
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);
|
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;
|
transfer.address += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::DoState(PointerWrap& p)
|
void CEXIEthernetBase::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
p.DoArray(tx_fifo.get(), BBA_TXFIFO_SIZE);
|
p.DoArray(&m_tx_fifo, BBA_TXFIFO_SIZE);
|
||||||
p.DoArray(mBbaMem.get(), BBA_MEM_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));
|
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));
|
return IsMXCommand(data) ? !!(data & (1 << 30)) : !!(data & (1 << 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* CEXIETHERNET::GetRegisterName() const
|
const char* CEXIEthernetBase::GetRegisterName() const
|
||||||
{
|
{
|
||||||
#define STR_RETURN(x) \
|
#define STR_RETURN(x) \
|
||||||
case x: \
|
case x: \
|
||||||
@@ -285,16 +283,16 @@ const char* CEXIETHERNET::GetRegisterName() const
|
|||||||
#undef STR_RETURN
|
#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;
|
m_bba_mem.ncrb = NCRB_PR;
|
||||||
mBbaMem[BBA_NWAYC] = NWAYC_LTE | NWAYC_ANE;
|
m_bba_mem.nwayc = NWAYC_LTE | NWAYC_ANE;
|
||||||
mBbaMem[BBA_MISC] = MISC1_TPF | MISC1_TPH | MISC1_TXF | MISC1_TXH;
|
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)
|
switch (transfer.address)
|
||||||
{
|
{
|
||||||
@@ -306,7 +304,7 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
|
|||||||
Activate();
|
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");
|
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
|
// 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
|
// Technically transfer DMA status is kept in TXDMA - not implemented
|
||||||
|
|
||||||
@@ -362,55 +360,57 @@ void CEXIETHERNET::MXCommandHandler(u32 data, u32 size)
|
|||||||
default:
|
default:
|
||||||
for (int i = size - 1; i >= 0; i--)
|
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;
|
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
|
// In direct mode, the hardware handles creating the state required by the
|
||||||
// GMAC instead of finagling with packet descriptors and such
|
// 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);
|
m_bba_mem.txfifocnt += size;
|
||||||
|
|
||||||
*tx_fifo_count += size;
|
|
||||||
// TODO: not sure this mask is correct.
|
// TODO: not sure this mask is correct.
|
||||||
// However, BBA_TXFIFOCNT should never get even close to this amount,
|
// However, BBA_TXFIFOCNT should never get even close to this amount,
|
||||||
// so it shouldn't matter
|
// 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.");
|
ERROR_LOG(SP1, "tx packet buffer not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::SendComplete()
|
void CEXIEthernetBase::SendComplete()
|
||||||
{
|
{
|
||||||
mBbaMem[BBA_NCRA] &= ~(NCRA_ST0 | NCRA_ST1);
|
m_bba_mem.ncra &= ~(NCRA_ST0 | NCRA_ST1);
|
||||||
*(u16*)&mBbaMem[BBA_TXFIFOCNT] = 0;
|
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;
|
exi_status.interrupt |= exi_status.TRANSFER;
|
||||||
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, 0);
|
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
|
// Calculate CRC
|
||||||
u32 crc = 0xffffffff;
|
u32 crc = 0xffffffff;
|
||||||
@@ -432,25 +432,25 @@ inline u8 CEXIETHERNET::HashIndex(const u8* dest_eth_addr)
|
|||||||
return crc >> 26;
|
return crc >> 26;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool CEXIETHERNET::RecvMACFilter()
|
inline bool CEXIEthernetBase::RecvMACFilter() const
|
||||||
{
|
{
|
||||||
static u8 const broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
static u8 const broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||||
|
|
||||||
// Accept all destination addrs?
|
// Accept all destination addrs?
|
||||||
if (mBbaMem[BBA_NCRB] & NCRB_PR)
|
if (m_bba_mem.ncrb & NCRB_PR)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Unicast?
|
// 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?
|
// 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
|
// Accept all multicast
|
||||||
return true;
|
return true;
|
||||||
@@ -458,25 +458,26 @@ inline bool CEXIETHERNET::RecvMACFilter()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Lookup the dest eth address in the hashmap
|
// Lookup the dest eth address in the hashmap
|
||||||
u16 index = HashIndex(mRecvBuffer.get());
|
u16 index = HashIndex(&m_recv_buffer[0]);
|
||||||
return !!(mBbaMem[BBA_NAFR_MAR0 + index / 8] & (1 << (index % 8)));
|
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 (m_bba_mem.rwp + 1 == page_ptr(BBA_RHBP))
|
||||||
|
m_bba_mem.rwp = page_ptr(BBA_BP);
|
||||||
if (*rwp + 1 == page_ptr(BBA_RHBP))
|
|
||||||
*rwp = page_ptr(BBA_BP);
|
|
||||||
else
|
else
|
||||||
(*rwp)++;
|
m_bba_mem.rwp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is on the critical path for receiving data.
|
// This function is on the critical path for receiving data.
|
||||||
// Be very careful about calling into the logger and other slow things
|
// 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* write_ptr;
|
||||||
u8* end_ptr;
|
u8* end_ptr;
|
||||||
u8* read_ptr;
|
u8* read_ptr;
|
||||||
@@ -488,23 +489,23 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||||||
goto wait_for_next;
|
goto wait_for_next;
|
||||||
|
|
||||||
#ifdef BBA_TRACK_PAGE_PTRS
|
#ifdef BBA_TRACK_PAGE_PTRS
|
||||||
INFO_LOG(SP1, "RecvHandlePacket %x\n%s", mRecvBufferLength,
|
INFO_LOG(SP1, "RecvHandlePacket %x\n%s", m_recv_buffer_length,
|
||||||
ArrayToString(mRecvBuffer, mRecvBufferLength, 0x100).c_str());
|
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),
|
INFO_LOG(SP1, "%x %x %x %x", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP),
|
||||||
page_ptr(BBA_RHBP));
|
page_ptr(BBA_RHBP));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
write_ptr = ptr_from_page_ptr(BBA_RWP);
|
write_ptr = PtrFromPagePtr(BBA_RWP);
|
||||||
end_ptr = ptr_from_page_ptr(BBA_RHBP);
|
end_ptr = PtrFromPagePtr(BBA_RHBP);
|
||||||
read_ptr = ptr_from_page_ptr(BBA_RRP);
|
read_ptr = PtrFromPagePtr(BBA_RRP);
|
||||||
|
|
||||||
descriptor = (Descriptor*)write_ptr;
|
descriptor = (Descriptor*)write_ptr;
|
||||||
write_ptr += 4;
|
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)
|
if (off == 0xff)
|
||||||
{
|
{
|
||||||
@@ -513,7 +514,7 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (write_ptr == end_ptr)
|
if (write_ptr == end_ptr)
|
||||||
write_ptr = ptr_from_page_ptr(BBA_BP);
|
write_ptr = PtrFromPagePtr(BBA_BP);
|
||||||
|
|
||||||
if (write_ptr == read_ptr)
|
if (write_ptr == read_ptr)
|
||||||
{
|
{
|
||||||
@@ -529,13 +530,13 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||||||
inc MPC instead of receiving packets
|
inc MPC instead of receiving packets
|
||||||
*/
|
*/
|
||||||
status |= DESC_FO | DESC_BF;
|
status |= DESC_FO | DESC_BF;
|
||||||
mBbaMem[BBA_IR] |= mBbaMem[BBA_IMR] & INT_RBF;
|
m_bba_mem.ir |= m_bba_mem.imr & INT_RBF;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align up to next page
|
// Align up to next page
|
||||||
if ((mRecvBufferLength + 4) % 256)
|
if ((m_recv_buffer_length + 4) % 256)
|
||||||
inc_rwp();
|
inc_rwp();
|
||||||
|
|
||||||
#ifdef BBA_TRACK_PAGE_PTRS
|
#ifdef BBA_TRACK_PAGE_PTRS
|
||||||
@@ -544,14 +545,14 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Is the current frame multicast?
|
// Is the current frame multicast?
|
||||||
if (mRecvBuffer[0] & 0x01)
|
if (m_recv_buffer[0] & 0x01)
|
||||||
status |= DESC_MF;
|
status |= DESC_MF;
|
||||||
|
|
||||||
if (status & DESC_BF)
|
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
|
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
|
// 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;
|
exi_status.interrupt |= exi_status.TRANSFER;
|
||||||
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::NON_CPU, 0);
|
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::NON_CPU, 0);
|
||||||
@@ -578,7 +579,7 @@ bool CEXIETHERNET::RecvHandlePacket()
|
|||||||
}
|
}
|
||||||
|
|
||||||
wait_for_next:
|
wait_for_next:
|
||||||
if (mBbaMem[BBA_NCRA] & NCRA_SR)
|
if (m_bba_mem.ncra & NCRA_SR)
|
||||||
RecvStart();
|
RecvStart();
|
||||||
|
|
||||||
return true;
|
return true;
|
@@ -4,17 +4,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Common/Flag.h"
|
|
||||||
#include "Core/HW/EXI/EXI_Device.h"
|
#include "Core/HW/EXI/EXI_Device.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
namespace ExpansionInterface
|
namespace ExpansionInterface
|
||||||
@@ -131,6 +124,7 @@ enum
|
|||||||
BBA_NAFR_PAR3 = 0x23,
|
BBA_NAFR_PAR3 = 0x23,
|
||||||
BBA_NAFR_PAR4 = 0x24,
|
BBA_NAFR_PAR4 = 0x24,
|
||||||
BBA_NAFR_PAR5 = 0x25,
|
BBA_NAFR_PAR5 = 0x25,
|
||||||
|
|
||||||
BBA_NAFR_MAR0 = 0x26,
|
BBA_NAFR_MAR0 = 0x26,
|
||||||
BBA_NAFR_MAR1 = 0x27,
|
BBA_NAFR_MAR1 = 0x27,
|
||||||
BBA_NAFR_MAR2 = 0x28,
|
BBA_NAFR_MAR2 = 0x28,
|
||||||
@@ -157,14 +151,6 @@ enum
|
|||||||
BBA_SI_ACTRL2 = 0x60
|
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
|
enum
|
||||||
{
|
{
|
||||||
EXI_DEVTYPE_ETHER = 0x04020200
|
EXI_DEVTYPE_ETHER = 0x04020200
|
||||||
@@ -194,13 +180,11 @@ enum RecvStatus
|
|||||||
DESC_RERR = 0x80
|
DESC_RERR = 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BBA_RECV_SIZE 0x800
|
class CEXIEthernetBase : public IEXIDevice
|
||||||
|
|
||||||
class CEXIETHERNET : public IEXIDevice
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEXIETHERNET();
|
CEXIEthernetBase();
|
||||||
virtual ~CEXIETHERNET();
|
|
||||||
void SetCS(int cs) override;
|
void SetCS(int cs) override;
|
||||||
bool IsPresent() const override;
|
bool IsPresent() const override;
|
||||||
bool IsInterruptSet() override;
|
bool IsInterruptSet() override;
|
||||||
@@ -210,7 +194,100 @@ public:
|
|||||||
void DMARead(u32 addr, u32 size) override;
|
void DMARead(u32 addr, u32 size) override;
|
||||||
void DoState(PointerWrap& p) 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<u8, BBA_MEM_SIZE> 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<u8, 6> nafr_par; //0x20
|
||||||
|
std::array<u8, 8> 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<u8, BBA_TXFIFO_SIZE> m_tx_fifo;
|
||||||
|
|
||||||
|
std::array<u8, BBA_RECV_SIZE> m_recv_buffer;
|
||||||
|
u32 m_recv_buffer_length = 0;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
@@ -273,58 +350,5 @@ private:
|
|||||||
word |= next_page & 0xfff;
|
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<u8[]> mBbaMem;
|
|
||||||
std::unique_ptr<u8[]> 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<u8[]> mRecvBuffer;
|
|
||||||
u32 mRecvBufferLength = 0;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
HANDLE mHAdapter = INVALID_HANDLE_VALUE;
|
|
||||||
OVERLAPPED mReadOverlapped = {};
|
|
||||||
OVERLAPPED mWriteOverlapped = {};
|
|
||||||
std::vector<u8> 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
|
} // namespace ExpansionInterface
|
52
Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP.h
Normal file
52
Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2008 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <vector>
|
||||||
|
#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<u8> 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
|
104
Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
Normal file
104
Source/Core/Core/HW/EXI/EXI_DeviceEthernetTAP_Apple.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2008 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#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
|
@@ -11,7 +11,7 @@
|
|||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/HW/EXI/EXI_Device.h"
|
#include "Core/HW/EXI/EXI_Device.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
|
#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -25,10 +25,24 @@
|
|||||||
|
|
||||||
namespace ExpansionInterface
|
namespace ExpansionInterface
|
||||||
{
|
{
|
||||||
#define NOTIMPLEMENTED(Name) \
|
#define NOTIMPLEMENTED \
|
||||||
NOTICE_LOG(SP1, "CEXIETHERNET::%s not implemented for your UNIX", Name);
|
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__
|
#ifdef __linux__
|
||||||
if (IsActivated())
|
if (IsActivated())
|
||||||
@@ -37,7 +51,7 @@ bool CEXIETHERNET::Activate()
|
|||||||
// Assumes that there is a TAP device named "Dolphin" preconfigured for
|
// Assumes that there is a TAP device named "Dolphin" preconfigured for
|
||||||
// bridge/NAT/whatever the user wants it configured.
|
// 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");
|
ERROR_LOG(SP1, "Couldn't open /dev/net/tun, unable to init BBA");
|
||||||
return false;
|
return false;
|
||||||
@@ -53,12 +67,12 @@ bool CEXIETHERNET::Activate()
|
|||||||
strncpy(ifr.ifr_name, StringFromFormat("Dolphin%d", i).c_str(), IFNAMSIZ);
|
strncpy(ifr.ifr_name, StringFromFormat("Dolphin%d", i).c_str(), IFNAMSIZ);
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0)
|
if ((err = ioctl(m_fd, TUNSETIFF, (void*)&ifr)) < 0)
|
||||||
{
|
{
|
||||||
if (i == (MAX_INTERFACES - 1))
|
if (i == (MAX_INTERFACES - 1))
|
||||||
{
|
{
|
||||||
close(fd);
|
close(m_fd);
|
||||||
fd = -1;
|
m_fd = -1;
|
||||||
ERROR_LOG(SP1, "TUNSETIFF failed: Interface=%s err=%d", ifr.ifr_name, err);
|
ERROR_LOG(SP1, "TUNSETIFF failed: Interface=%s err=%d", ifr.ifr_name, err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -68,46 +82,29 @@ bool CEXIETHERNET::Activate()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ioctl(fd, TUNSETNOCSUM, 1);
|
ioctl(m_fd, TUNSETNOCSUM, 1);
|
||||||
|
|
||||||
INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name);
|
INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name);
|
||||||
return RecvInit();
|
return RecvInit();
|
||||||
#else
|
#else
|
||||||
NOTIMPLEMENTED("Activate");
|
NOTIMPLEMENTED;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::Deactivate()
|
bool CEXIEthernetTAP::IsActivated() const
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
close(fd);
|
return m_fd != -1;
|
||||||
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;
|
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
|
bool CEXIEthernetTAP::SendFrame(const u8* frame, u32 size)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
DEBUG_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str());
|
int writtenBytes = write(m_fd, frame, size);
|
||||||
|
|
||||||
int writtenBytes = write(fd, frame, size);
|
|
||||||
if ((u32)writtenBytes != size)
|
if ((u32)writtenBytes != size)
|
||||||
{
|
{
|
||||||
ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
NOTIMPLEMENTED("SendFrame");
|
NOTIMPLEMENTED;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
bool CEXIEthernetTAP::RecvInit()
|
||||||
void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
|
|
||||||
{
|
{
|
||||||
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_set rfds;
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_SET(self->fd, &rfds);
|
FD_SET(self->m_fd, &rfds);
|
||||||
|
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
timeout.tv_sec = 0;
|
timeout.tv_sec = 0;
|
||||||
timeout.tv_usec = 50000;
|
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;
|
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)
|
if (readBytes < 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes);
|
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",
|
self->m_recv_buffer_length = readBytes;
|
||||||
ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str());
|
|
||||||
self->mRecvBufferLength = readBytes;
|
|
||||||
self->RecvHandlePacket();
|
self->RecvHandlePacket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
} // namespace ExpansionInterface
|
@@ -2,13 +2,12 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// 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/Assert.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/HW/EXI/EXI_Device.h"
|
#include "Core/HW/EXI/EXI_DeviceEthernetTAP.h"
|
||||||
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
|
|
||||||
|
|
||||||
namespace Win32TAPHelper
|
namespace Win32TAPHelper
|
||||||
{
|
{
|
||||||
@@ -167,7 +166,32 @@ bool OpenTAP(HANDLE& adapter, const std::basic_string<TCHAR>& device_guid)
|
|||||||
|
|
||||||
namespace ExpansionInterface
|
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())
|
if (IsActivated())
|
||||||
return true;
|
return true;
|
||||||
@@ -183,13 +207,13 @@ bool CEXIETHERNET::Activate()
|
|||||||
|
|
||||||
for (size_t i = 0; i < device_guids.size(); i++)
|
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());
|
INFO_LOG(SP1, "OPENED %s", device_guids.at(i).c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mHAdapter == INVALID_HANDLE_VALUE)
|
if (m_h_adapter == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
PanicAlert("Failed to open any TAP");
|
PanicAlert("Failed to open any TAP");
|
||||||
return false;
|
return false;
|
||||||
@@ -197,7 +221,7 @@ bool CEXIETHERNET::Activate()
|
|||||||
|
|
||||||
/* get driver version info */
|
/* get driver version info */
|
||||||
ULONG info[3];
|
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))
|
&len, nullptr))
|
||||||
{
|
{
|
||||||
INFO_LOG(SP1, "TAP-Win32 Driver Version %d.%d %s", info[0], info[1], info[2] ? "(DEBUG)" : "");
|
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' */
|
/* set driver media status to 'connected' */
|
||||||
ULONG status = TRUE;
|
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))
|
sizeof(status), &len, nullptr))
|
||||||
{
|
{
|
||||||
ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a"
|
ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a"
|
||||||
@@ -224,57 +248,32 @@ bool CEXIETHERNET::Activate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize read/write events */
|
/* initialize read/write events */
|
||||||
mReadOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
m_read_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
mWriteOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
m_write_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
if (mReadOverlapped.hEvent == nullptr || mWriteOverlapped.hEvent == nullptr)
|
if (m_read_overlapped.hEvent == nullptr || m_write_overlapped.hEvent == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mWriteBuffer.reserve(1518);
|
m_write_buffer.reserve(1518);
|
||||||
return RecvInit();
|
return RecvInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::Deactivate()
|
bool CEXIEthernetTAP::IsActivated() const
|
||||||
{
|
{
|
||||||
if (!IsActivated())
|
return m_h_adapter != INVALID_HANDLE_VALUE;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIETHERNET::IsActivated()
|
void CEXIEthernetTAP::ReadThreadHandler(CEXIEthernetTAP* self)
|
||||||
{
|
{
|
||||||
return mHAdapter != INVALID_HANDLE_VALUE;
|
while (!self->m_read_thread_shutdown.IsSet())
|
||||||
}
|
|
||||||
|
|
||||||
void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
|
|
||||||
{
|
|
||||||
while (!self->readThreadShutdown.IsSet())
|
|
||||||
{
|
{
|
||||||
DWORD transferred;
|
DWORD transferred;
|
||||||
|
|
||||||
// Read from TAP into internal buffer.
|
// Read from TAP into internal buffer.
|
||||||
if (ReadFile(self->mHAdapter, self->mRecvBuffer.get(), BBA_RECV_SIZE, &transferred,
|
if (ReadFile(self->m_h_adapter, &self->m_recv_buffer, BBA_RECV_SIZE, &transferred,
|
||||||
&self->mReadOverlapped))
|
&self->m_read_overlapped))
|
||||||
{
|
{
|
||||||
// Returning immediately is not likely to happen, but if so, reset the event state manually.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
@@ -286,7 +285,7 @@ void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Block until the read completes.
|
// 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 CancelIO was called, we should exit (the flag will be set).
|
||||||
if (GetLastError() == ERROR_OPERATION_ABORTED)
|
if (GetLastError() == ERROR_OPERATION_ABORTED)
|
||||||
@@ -299,38 +298,34 @@ void CEXIETHERNET::ReadThreadHandler(CEXIETHERNET* self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy to BBA buffer, and fire interrupt if enabled.
|
// Copy to BBA buffer, and fire interrupt if enabled.
|
||||||
DEBUG_LOG(SP1, "Received %u bytes:\n %s", transferred,
|
if (self->m_read_enabled.IsSet())
|
||||||
ArrayToString(self->mRecvBuffer.get(), transferred, 0x10).c_str());
|
|
||||||
if (self->readEnabled.IsSet())
|
|
||||||
{
|
{
|
||||||
self->mRecvBufferLength = transferred;
|
self->m_recv_buffer_length = transferred;
|
||||||
self->RecvHandlePacket();
|
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.
|
// Check for a background write. We can't issue another one until this one has completed.
|
||||||
DWORD transferred;
|
DWORD transferred;
|
||||||
if (mWritePending)
|
if (m_write_pending)
|
||||||
{
|
{
|
||||||
// Wait for previous write to complete.
|
// 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());
|
ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy to write buffer.
|
// Copy to write buffer.
|
||||||
mWriteBuffer.assign(frame, frame + size);
|
m_write_buffer.assign(frame, frame + size);
|
||||||
mWritePending = true;
|
m_write_pending = true;
|
||||||
|
|
||||||
// Queue async write.
|
// 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.
|
// Returning immediately is not likely to happen, but if so, reset the event state manually.
|
||||||
ResetEvent(mWriteOverlapped.hEvent);
|
ResetEvent(m_write_overlapped.hEvent);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -338,8 +333,8 @@ bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
|
|||||||
if (GetLastError() != ERROR_IO_PENDING)
|
if (GetLastError() != ERROR_IO_PENDING)
|
||||||
{
|
{
|
||||||
ERROR_LOG(SP1, "WriteFile failed (err=0x%X)", GetLastError());
|
ERROR_LOG(SP1, "WriteFile failed (err=0x%X)", GetLastError());
|
||||||
ResetEvent(mWriteOverlapped.hEvent);
|
ResetEvent(m_write_overlapped.hEvent);
|
||||||
mWritePending = false;
|
m_write_pending = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,19 +344,19 @@ bool CEXIETHERNET::SendFrame(const u8* frame, u32 size)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CEXIETHERNET::RecvInit()
|
bool CEXIEthernetTAP::RecvInit()
|
||||||
{
|
{
|
||||||
readThread = std::thread(ReadThreadHandler, this);
|
m_read_thread = std::thread(ReadThreadHandler, this);
|
||||||
return true;
|
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
|
} // namespace ExpansionInterface
|
@@ -48,6 +48,8 @@ add_executable(dolphin-emu
|
|||||||
Config/ARCodeWidget.cpp
|
Config/ARCodeWidget.cpp
|
||||||
Config/ARCodeWidget.h
|
Config/ARCodeWidget.h
|
||||||
Config/CheatCodeEditor.cpp
|
Config/CheatCodeEditor.cpp
|
||||||
|
Config/ARCodeWidget.cpp
|
||||||
|
Config/BBAConfigWidget.cpp
|
||||||
Config/CheatCodeEditor.h
|
Config/CheatCodeEditor.h
|
||||||
Config/CheatWarningWidget.cpp
|
Config/CheatWarningWidget.cpp
|
||||||
Config/CheatWarningWidget.h
|
Config/CheatWarningWidget.h
|
||||||
|
94
Source/Core/DolphinQt/Config/BBAConfigWidget.cpp
Normal file
94
Source/Core/DolphinQt/Config/BBAConfigWidget.cpp
Normal file
@@ -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 <QDialogButtonBox>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
29
Source/Core/DolphinQt/Config/BBAConfigWidget.h
Normal file
29
Source/Core/DolphinQt/Config/BBAConfigWidget.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2019 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
@@ -60,6 +60,7 @@
|
|||||||
<QtMoc Include="CheatsManager.h" />
|
<QtMoc Include="CheatsManager.h" />
|
||||||
<QtMoc Include="Config\CheatCodeEditor.h" />
|
<QtMoc Include="Config\CheatCodeEditor.h" />
|
||||||
<QtMoc Include="Config\ARCodeWidget.h" />
|
<QtMoc Include="Config\ARCodeWidget.h" />
|
||||||
|
<QtMoc Include="Config\BBAConfigWidget.h" />
|
||||||
<QtMoc Include="Config\CheatWarningWidget.h" />
|
<QtMoc Include="Config\CheatWarningWidget.h" />
|
||||||
<QtMoc Include="Config\ControllersWindow.h" />
|
<QtMoc Include="Config\ControllersWindow.h" />
|
||||||
<QtMoc Include="Config\FilesystemWidget.h" />
|
<QtMoc Include="Config\FilesystemWidget.h" />
|
||||||
@@ -178,6 +179,7 @@
|
|||||||
<ClCompile Include="$(QtMocOutPrefix)AdvancedWidget.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)AdvancedWidget.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)AspectRatioWidget.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)AspectRatioWidget.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)AudioPane.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)AudioPane.cpp" />
|
||||||
|
<ClCompile Include="$(QtMocOutPrefix)BBAConfigWidget.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)BlockUserInputFilter.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)BlockUserInputFilter.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)BreakpointWidget.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)BreakpointWidget.cpp" />
|
||||||
<ClCompile Include="$(QtMocOutPrefix)CheatCodeEditor.cpp" />
|
<ClCompile Include="$(QtMocOutPrefix)CheatCodeEditor.cpp" />
|
||||||
@@ -288,6 +290,7 @@
|
|||||||
<ClCompile Include="CheatsManager.cpp" />
|
<ClCompile Include="CheatsManager.cpp" />
|
||||||
<ClCompile Include="Config\CheatCodeEditor.cpp" />
|
<ClCompile Include="Config\CheatCodeEditor.cpp" />
|
||||||
<ClCompile Include="Config\ARCodeWidget.cpp" />
|
<ClCompile Include="Config\ARCodeWidget.cpp" />
|
||||||
|
<ClCompile Include="Config\BBAConfigWidget.cpp" />
|
||||||
<ClCompile Include="Config\CheatWarningWidget.cpp" />
|
<ClCompile Include="Config\CheatWarningWidget.cpp" />
|
||||||
<ClCompile Include="Config\ControllersWindow.cpp" />
|
<ClCompile Include="Config\ControllersWindow.cpp" />
|
||||||
<ClCompile Include="Config\FilesystemWidget.cpp" />
|
<ClCompile Include="Config\FilesystemWidget.cpp" />
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "Core/HW/EXI/EXI.h"
|
#include "Core/HW/EXI/EXI.h"
|
||||||
#include "Core/HW/GCMemcard/GCMemcard.h"
|
#include "Core/HW/GCMemcard/GCMemcard.h"
|
||||||
|
|
||||||
|
#include "DolphinQt/Config/BBAConfigWidget.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
#include "DolphinQt/GCMemcardManager.h"
|
#include "DolphinQt/GCMemcardManager.h"
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
@@ -103,7 +104,7 @@ void GameCubePane::CreateWidgets()
|
|||||||
for (const auto& entry :
|
for (const auto& entry :
|
||||||
{std::make_pair(tr("<Nothing>"), ExpansionInterface::EXIDEVICE_NONE),
|
{std::make_pair(tr("<Nothing>"), ExpansionInterface::EXIDEVICE_NONE),
|
||||||
std::make_pair(tr("Dummy"), ExpansionInterface::EXIDEVICE_DUMMY),
|
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);
|
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);
|
value == ExpansionInterface::EXIDEVICE_AGP || value == ExpansionInterface::EXIDEVICE_MIC);
|
||||||
break;
|
break;
|
||||||
case SLOT_SP1_INDEX:
|
case SLOT_SP1_INDEX:
|
||||||
has_config = (value == ExpansionInterface::EXIDEVICE_ETH);
|
has_config = (value == ExpansionInterface::EXIDEVICE_ETH_TAP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +171,9 @@ void GameCubePane::OnConfigPressed(int slot)
|
|||||||
QString filter;
|
QString filter;
|
||||||
bool memcard = false;
|
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:
|
case ExpansionInterface::EXIDEVICE_MEMORYCARD:
|
||||||
filter = tr("GameCube Memory Cards (*.raw *.gcp)");
|
filter = tr("GameCube Memory Cards (*.raw *.gcp)");
|
||||||
@@ -182,14 +185,14 @@ void GameCubePane::OnConfigPressed(int slot)
|
|||||||
case ExpansionInterface::EXIDEVICE_MIC:
|
case ExpansionInterface::EXIDEVICE_MIC:
|
||||||
MappingWindow(this, MappingWindow::Type::MAPPING_GC_MICROPHONE, slot).exec();
|
MappingWindow(this, MappingWindow::Type::MAPPING_GC_MICROPHONE, slot).exec();
|
||||||
return;
|
return;
|
||||||
case ExpansionInterface::EXIDEVICE_ETH:
|
case ExpansionInterface::EXIDEVICE_ETH_TAP:
|
||||||
{
|
{
|
||||||
bool ok;
|
BBAConfigWidget dialog(this);
|
||||||
const auto new_mac = QInputDialog::getText(
|
dialog.SetMacAddr(QString::fromStdString(SConfig::GetInstance().m_bba_mac));
|
||||||
this, tr("Broadband Adapter MAC address"), tr("Enter new Broadband Adapter MAC address:"),
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
QLineEdit::Normal, QString::fromStdString(SConfig::GetInstance().m_bba_mac), &ok);
|
{
|
||||||
if (ok)
|
SConfig::GetInstance().m_bba_mac = dialog.MacAddr().toStdString();
|
||||||
SConfig::GetInstance().m_bba_mac = new_mac.toStdString();
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -198,7 +201,7 @@ void GameCubePane::OnConfigPressed(int slot)
|
|||||||
|
|
||||||
QString filename = QFileDialog::getSaveFileName(
|
QString filename = QFileDialog::getSaveFileName(
|
||||||
this, tr("Choose a file to open"), QString::fromStdString(File::GetUserPath(D_GCUSER_IDX)),
|
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())
|
if (filename.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user