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;