diff --git a/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp b/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp index f1b9fe88ae..b92e94e567 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp @@ -17,17 +17,47 @@ #include "EXI_Device.h" #include "EXI_DeviceGecko.h" +//#pragma optimize("",off) +THREAD_RETURN ClientThreadFunc(void *arg) +{ + ((GeckoSockServer*)arg)->ClientThread(); + return 0; +} -#include "SFML/Network.hpp" -#include "Thread.h" -#include +int GeckoSockServer::client_count; +Common::Thread *GeckoSockServer::connectionThread = NULL; +volatile bool GeckoSockServer::server_running; +std::queue GeckoSockServer::waiting_socks; +Common::CriticalSection GeckoSockServer::connection_lock; -static Common::Thread *connectionThread = NULL; -static std::queue waiting_socks; -static Common::CriticalSection cs_gecko; -namespace { volatile bool server_running; } +GeckoSockServer::GeckoSockServer() + : clientThread(NULL) + , client_running(false) +{ + if (!connectionThread) + connectionThread = new Common::Thread(&GeckoConnectionWaiter, (void*)0); +} -static THREAD_RETURN GeckoConnectionWaiter(void*) +GeckoSockServer::~GeckoSockServer() +{ + if (client_running) + { + client_running = false; + clientThread->WaitForDeath(); + } + delete clientThread; + clientThread = NULL; + + if (--client_count <= 0) + { + server_running = false; + connectionThread->WaitForDeath(); + delete connectionThread; + connectionThread = NULL; + } +} + +THREAD_RETURN GeckoSockServer::GeckoConnectionWaiter(void*) { server_running = true; @@ -45,9 +75,9 @@ static THREAD_RETURN GeckoConnectionWaiter(void*) { if (server.Accept(new_client) == sf::Socket::Done) { - cs_gecko.Enter(); + connection_lock.Enter(); waiting_socks.push(new_client); - cs_gecko.Leave(); + connection_lock.Leave(); } SLEEP(1); } @@ -55,73 +85,79 @@ static THREAD_RETURN GeckoConnectionWaiter(void*) return 0; } -void GeckoConnectionWaiter_Shutdown() -{ - server_running = false; - if (connectionThread) - { - connectionThread->WaitForDeath(); - delete connectionThread; - connectionThread = NULL; - } -} - -static bool GetAvailableSock(sf::SocketTCP& sock_to_fill) +bool GeckoSockServer::GetAvailableSock(sf::SocketTCP &sock_to_fill) { bool sock_filled = false; - cs_gecko.Enter(); + connection_lock.Enter(); if (waiting_socks.size()) { sock_to_fill = waiting_socks.front(); + if (clientThread) + { + if (client_running) + { + client_running = false; + clientThread->WaitForDeath(); + } + delete clientThread; + clientThread = NULL; + } + clientThread = new Common::Thread(ClientThreadFunc, this); + client_count++; waiting_socks.pop(); sock_filled = true; } - cs_gecko.Leave(); + connection_lock.Leave(); return sock_filled; } -GeckoSockServer::GeckoSockServer() +void GeckoSockServer::ClientThread() { - if (!connectionThread) - connectionThread = new Common::Thread(GeckoConnectionWaiter, (void*)0); -} + client_running = true; + + Common::SetCurrentThreadName("Gecko Client"); + + client.SetBlocking(false); + + while (client_running) + { + u8 data; + std::size_t got = 0; + + transfer_lock.Enter(); + if (client.Receive((char*)&data, sizeof(data), got) + == sf::Socket::Disconnected) + client_running = false; + if (got) + recv_fifo.push(data); + + if (send_fifo.size()) + { + if (client.Send((char*)&send_fifo.front(), sizeof(u8)) + == sf::Socket::Disconnected) + client_running = false; + send_fifo.pop(); + } + transfer_lock.Leave(); + SLEEP(1); + } -GeckoSockServer::~GeckoSockServer() -{ client.Close(); } -CEXIGecko::CEXIGecko() - : m_uPosition(0) - , recv_fifo(false) -{ -} - -void CEXIGecko::SetCS(int cs) -{ - if (cs) - m_uPosition = 0; -} - -bool CEXIGecko::IsPresent() -{ - return true; -} - void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize) { + // We don't really care about _uSize + (void)_uSize; + if (!client.IsValid()) if (!GetAvailableSock(client)) - {} ;// TODO nothing for now + return; // for debug u32 oldval = _uData; - // TODO do we really care about _uSize? - - u8 data = 0; - std::size_t got; switch (_uData >> 28) { @@ -130,26 +166,31 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize) break; case CMD_LED_ON: break; - // maybe should only | 2bytes? + case CMD_INIT: _uData = ident; break; + // PC -> Gecko + // |= 0x08000000 if successful case CMD_RECV: - // TODO recv - client.Receive((char*)&data, sizeof(data), got); - recv_fifo = !!got; - if (recv_fifo) - _uData = 0x08000000 | (data << 16); + transfer_lock.Enter(); + if (recv_fifo.size()) + { + _uData = 0x08000000 | (recv_fifo.front() << 16); + recv_fifo.pop(); + } + transfer_lock.Leave(); break; // Gecko -> PC + // |= 0x04000000 if successful case CMD_SEND: - data = (_uData >> 20) & 0xff; - // TODO send - client.Send((char*)&data, sizeof(data)); - // If successful - _uData |= 0x04000000; + transfer_lock.Enter(); + send_fifo.push(_uData >> 20); + transfer_lock.Leave(); + _uData = 0x04000000; break; + // Check if ok for Gecko -> PC, or FIFO full // |= 0x04000000 if FIFO is not full case CMD_CHK_TX: @@ -158,13 +199,14 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize) // Check if data in FIFO for PC -> Gecko, or FIFO empty // |= 0x04000000 if data in recv FIFO case CMD_CHK_RX: - //_uData = recv_fifo ? 0x04000000 : 0; - _uData = 0x04000000; + transfer_lock.Enter(); + _uData = recv_fifo.size() ? 0x04000000 : 0; + transfer_lock.Leave(); break; + default: ERROR_LOG(EXPANSIONINTERFACE, "Uknown USBGecko command %x", _uData); break; } - - if (_uData) { ERROR_LOG(EXPANSIONINTERFACE, "rw %x %08x %08x", oldval, _uData, _uSize); } } +//#pragma optimize("",on) \ No newline at end of file diff --git a/Source/Core/Core/Src/HW/EXI_DeviceGecko.h b/Source/Core/Core/Src/HW/EXI_DeviceGecko.h index 0d5a6f7a9d..93c9f2fbda 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceGecko.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceGecko.h @@ -19,6 +19,8 @@ #define _EXIDEVICE_GECKO_H #include "SFML/Network.hpp" +#include "Thread.h" +#include class GeckoSockServer : public sf::SocketTCP @@ -26,9 +28,28 @@ class GeckoSockServer public: GeckoSockServer(); ~GeckoSockServer(); + bool GetAvailableSock(sf::SocketTCP &sock_to_fill); -//private: + // Client for this server object sf::SocketTCP client; + void ClientThread(); + Common::Thread *clientThread; + Common::CriticalSection transfer_lock; + + std::queue send_fifo; + std::queue recv_fifo; + +private: + static int client_count; + volatile bool client_running; + + // Only ever one server thread + static THREAD_RETURN GeckoConnectionWaiter(void*); + + static volatile bool server_running; + static Common::Thread *connectionThread; + static std::queue waiting_socks; + static Common::CriticalSection connection_lock; }; class CEXIGecko @@ -36,9 +57,8 @@ class CEXIGecko , private GeckoSockServer { public: - CEXIGecko(); - void SetCS(int _iCS); - bool IsPresent(); + CEXIGecko() {} + bool IsPresent() { return true; } void ImmReadWrite(u32 &_uData, u32 _uSize); private: @@ -53,9 +73,6 @@ private: CMD_CHK_RX = 0xd, }; - u32 m_uPosition; - bool recv_fifo; - static const u32 ident = 0x04700000; };