diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj
index dc0f66f830..f83c42385d 100644
--- a/Source/Core/Core/Core.vcproj
+++ b/Source/Core/Core/Core.vcproj
@@ -583,6 +583,14 @@
RelativePath=".\Src\HW\EXI_DeviceEthernet.h"
>
+
+
+
+
diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp
index 2af1ae1e88..0d28c7ce08 100644
--- a/Source/Core/Core/Src/HW/EXI_Channel.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Channel.cpp
@@ -233,13 +233,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
{
case EXI_READ: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break;
case EXI_WRITE: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break;
- case EXI_READWRITE:
- ERROR_LOG(SP1, "RW UNSUPPORTED");
-/* Only used by USBGecko?
- pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1);
- m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); */
- break;
-
+ case EXI_READWRITE: pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); break;
default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW);
}
m_Control.TSTART = 0;
@@ -269,4 +263,4 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
m_ImmData = _iValue;
break;
}
-}
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp
index ed7f560677..fc73f4e0d8 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Device.cpp
@@ -24,13 +24,14 @@
#include "EXI_DeviceMic.h"
#include "EXI_DeviceEthernet.h"
#include "EXI_DeviceAMBaseboard.h"
+#include "EXI_DeviceGecko.h"
#include "../Core.h"
#include "../ConfigManager.h"
// --- interface IEXIDevice ---
-void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
+void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
{
while (_uSize--)
{
@@ -137,6 +138,10 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
return new CEXIAMBaseboard();
break;
+ case EXIDEVICE_GECKO:
+ return new CEXIGecko();
+ break;
+
case EXIDEVICE_NONE:
default:
return new IEXIDevice();
diff --git a/Source/Core/Core/Src/HW/EXI_Device.h b/Source/Core/Core/Src/HW/EXI_Device.h
index 173cec0b25..4cc613950b 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.h
+++ b/Source/Core/Core/Src/HW/EXI_Device.h
@@ -30,7 +30,8 @@ private:
public:
// Immediate copy functions
virtual void ImmWrite(u32 _uData, u32 _uSize);
- virtual u32 ImmRead(u32 _uSize);
+ virtual u32 ImmRead(u32 _uSize);
+ virtual void ImmReadWrite(u32 &/*_uData*/, u32 /*_uSize*/) {}
// DMA copy functions
virtual void DMAWrite(u32 _uAddr, u32 _uSize);
@@ -59,6 +60,7 @@ enum TEXIDevices
EXIDEVICE_MIC,
EXIDEVICE_ETH,
EXIDEVICE_AM_BASEBOARD,
+ EXIDEVICE_GECKO,
EXIDEVICE_NONE = (u8)-1
};
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp b/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp
new file mode 100644
index 0000000000..f331d9084f
--- /dev/null
+++ b/Source/Core/Core/Src/HW/EXI_DeviceGecko.cpp
@@ -0,0 +1,170 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "EXI_Device.h"
+#include "EXI_DeviceGecko.h"
+
+#include "SFML/Network.hpp"
+#include "Thread.h"
+#include
+
+static Common::Thread *connectionThread = NULL;
+static std::queue waiting_socks;
+static Common::CriticalSection cs_gecko;
+namespace { volatile bool server_running; }
+
+static THREAD_RETURN GeckoConnectionWaiter(void*)
+{
+ server_running = true;
+
+ Common::SetCurrentThreadName("Gecko Connection Waiter");
+
+ sf::SocketTCP server;
+ // "dolphin gecko"
+ if (!server.Listen(0xd6ec))
+ return 0;
+
+ server.SetBlocking(false);
+
+ sf::SocketTCP new_client;
+ while (server_running)
+ {
+ if (server.Accept(new_client) == sf::Socket::Done)
+ {
+ cs_gecko.Enter();
+ waiting_socks.push(new_client);
+ cs_gecko.Leave();
+ }
+ SLEEP(1);
+ }
+ server.Close();
+ 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 sock_filled = false;
+
+ cs_gecko.Enter();
+ if (waiting_socks.size())
+ {
+ sock_to_fill = waiting_socks.front();
+ waiting_socks.pop();
+ sock_filled = true;
+ }
+ cs_gecko.Leave();
+
+ return sock_filled;
+}
+
+GeckoSockServer::GeckoSockServer()
+{
+ if (!connectionThread)
+ connectionThread = new Common::Thread(GeckoConnectionWaiter, (void*)0);
+}
+
+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)
+{
+ if (!client.IsValid())
+ if (!GetAvailableSock(client))
+ ;// TODO nothing for now
+
+ // for debug
+ u32 oldval = _uData;
+ // TODO do we really care about _uSize?
+
+ u8 data = 0;
+ std::size_t got;
+
+ switch (_uData >> 28)
+ {
+ // maybe do something fun later
+ case CMD_LED_OFF:
+ break;
+ case CMD_LED_ON:
+ break;
+ // maybe should only | 2bytes?
+ case CMD_INIT:
+ _uData = ident;
+ break;
+ // PC -> Gecko
+ case CMD_RECV:
+ // TODO recv
+ client.Receive((char*)&data, sizeof(data), got);
+ recv_fifo = !!got;
+ if (recv_fifo)
+ _uData = 0x08000000 | (data << 16);
+ break;
+ // Gecko -> PC
+ case CMD_SEND:
+ data = (_uData >> 20) & 0xff;
+ // TODO send
+ client.Send((char*)&data, sizeof(data));
+ // If successful
+ _uData |= 0x04000000;
+ break;
+ // Check if ok for Gecko -> PC, or FIFO full
+ // |= 0x04000000 if FIFO is not full
+ case CMD_CHK_TX:
+ _uData = 0x04000000;
+ break;
+ // 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;
+ break;
+ default:
+ ERROR_LOG(EXPANSIONINTERFACE, "Uknown USBGecko command %x", _uData);
+ break;
+ }
+
+ if (_uData) { ERROR_LOG(EXPANSIONINTERFACE, "rw %x %08x %08x", oldval, _uData, _uSize); }
+}
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceGecko.h b/Source/Core/Core/Src/HW/EXI_DeviceGecko.h
new file mode 100644
index 0000000000..38c57ab517
--- /dev/null
+++ b/Source/Core/Core/Src/HW/EXI_DeviceGecko.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _EXIDEVICE_GECKO_H
+#define _EXIDEVICE_GECKO_H
+
+#include "SFML/Network.hpp"
+
+class GeckoSockServer
+ : public sf::SocketTCP
+{
+public:
+ GeckoSockServer();
+ ~GeckoSockServer();
+
+//private:
+ sf::SocketTCP client;
+};
+
+class CEXIGecko
+ : public IEXIDevice
+ , private GeckoSockServer
+{
+public:
+ CEXIGecko();
+ void SetCS(int _iCS);
+ bool IsPresent();
+ void ImmReadWrite(u32 &_uData, u32 _uSize);
+
+private:
+ enum
+ {
+ CMD_LED_OFF = 0x7,
+ CMD_LED_ON = 0x8,
+ CMD_INIT = 0x9,
+ CMD_RECV = 0xa,
+ CMD_SEND = 0xb,
+ CMD_CHK_TX = 0xc,
+ CMD_CHK_RX = 0xd,
+ };
+
+ u32 m_uPosition;
+ bool recv_fifo;
+
+ static const u32 ident = 0x04700000;
+};
+
+#endif
+
diff --git a/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp b/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp
index 7df516d8a2..17b069bc85 100644
--- a/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp
+++ b/Source/Core/Core/Src/HW/SI_DeviceGBA.cpp
@@ -25,7 +25,7 @@
static Common::Thread *connectionThread = NULL;
static std::queue waiting_socks;
static Common::CriticalSection cs_gba;
-volatile bool server_running;
+namespace { volatile bool server_running; }
// --- GameBoy Advance "Link Cable" ---
@@ -36,6 +36,7 @@ THREAD_RETURN GBAConnectionWaiter(void*)
Common::SetCurrentThreadName("GBA Connection Waiter");
sf::SocketTCP server;
+ // "dolphin gba"
if (!server.Listen(0xd6ba))
return 0;
@@ -101,11 +102,8 @@ void GBASockServer::Transfer(char* si_buffer)
if (!GetAvailableSock(client))
return;
- current_data[0] = si_buffer[3];
- current_data[1] = si_buffer[2];
- current_data[2] = si_buffer[1];
- current_data[3] = si_buffer[0];
- current_data[4] = si_buffer[7];
+ for (int i = 0; i < 5; i++)
+ current_data[i] = si_buffer[i ^ 3];
u8 cmd = *current_data;
@@ -138,11 +136,8 @@ void GBASockServer::Transfer(char* si_buffer)
(unsigned int)num_received, (unsigned int)num_expecting);
#endif
- si_buffer[0] = current_data[3];
- si_buffer[1] = current_data[2];
- si_buffer[2] = current_data[1];
- si_buffer[3] = current_data[0];
- si_buffer[7] = current_data[4];
+ for (int i = 0; i < 5; i++)
+ si_buffer[i ^ 3] = current_data[i];
}
CSIDevice_GBA::CSIDevice_GBA(int _iDeviceNumber)
diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp
index b768b1146e..021b347e93 100644
--- a/Source/Core/DolphinWX/Src/ConfigMain.cpp
+++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp
@@ -75,6 +75,7 @@ static const wxLanguage langIds[] =
#define EXIDEV_MIC_STR _trans("Mic")
#define EXIDEV_BBA_STR "BBA"
#define EXIDEV_AM_BB_STR _trans("AM-Baseboard")
+#define EXIDEV_GECKO_STR "USBGecko"
#ifdef WIN32
//only used with xgettext to be picked up as translatable string.
@@ -564,7 +565,7 @@ void CConfigMain::CreateGUIControls()
GCEXIDeviceText[0] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTA_TEXT, wxT("Slot A"), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTB_TEXT, wxT("Slot B"), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SP1_TEXT, wxT("SP1 "), wxDefaultPosition, wxDefaultSize);
- const wxString SlotDevices[] = {_(DEV_NONE_STR), _(DEV_DUMMY_STR), _(EXIDEV_MEMCARD_STR)
+ const wxString SlotDevices[] = {_(DEV_NONE_STR), _(DEV_DUMMY_STR), _(EXIDEV_MEMCARD_STR), _(EXIDEV_GECKO_STR)
#if HAVE_PORTAUDIO
, _(EXIDEV_MIC_STR)
#endif
@@ -591,7 +592,7 @@ void CConfigMain::CreateGUIControls()
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
break;
case EXIDEVICE_MIC:
- GCEXIDevice[i]->SetStringSelection(SlotDevices[3]);
+ GCEXIDevice[i]->SetStringSelection(SlotDevices[4]);
break;
case EXIDEVICE_ETH:
GCEXIDevice[i]->SetStringSelection(SP1Devices[2]);
@@ -599,6 +600,9 @@ void CConfigMain::CreateGUIControls()
case EXIDEVICE_AM_BASEBOARD:
GCEXIDevice[i]->SetStringSelection(SP1Devices[3]);
break;
+ case EXIDEVICE_GECKO:
+ GCEXIDevice[i]->SetStringSelection(SlotDevices[3]);
+ break;
case EXIDEVICE_DUMMY:
default:
GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
@@ -1039,6 +1043,8 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
tempType = EXIDEVICE_ETH;
else if (!deviceName.compare(EXIDEV_AM_BB_STR))
tempType = EXIDEVICE_AM_BASEBOARD;
+ else if (!deviceName.compare(EXIDEV_GECKO_STR))
+ tempType = EXIDEVICE_GECKO;
else if (!deviceName.compare(DEV_NONE_STR))
tempType = EXIDEVICE_NONE;
else