Merge pull request #3455 from Sonicadvance1/GC_adapter_android

[Android] Add support for the Wii U Gamecube adapter under Android.
This commit is contained in:
Ryan Houdek committed 2016-01-06 15:07:09 -05:00
commit 342496563d
29 files changed
+950 -226

No files matched your search

+2 -2
View File
@@ -113,6 +113,7 @@ set(SRCS ActionReplay.cpp
HW/SI_Device.cpp
HW/SI_DeviceDanceMat.cpp
HW/SI_DeviceGBA.cpp
HW/SI_DeviceGCAdapter.cpp
HW/SI_DeviceGCController.cpp
HW/SI_DeviceGCSteeringWheel.cpp
HW/SI_DeviceKeyboard.cpp
@@ -239,8 +240,7 @@ set(LIBS
if(LIBUSB_FOUND)
# Using shared LibUSB
set(LIBS ${LIBS} ${LIBUSB_LIBRARIES})
set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp
HW/SI_GCAdapter.cpp)
set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp)
endif(LIBUSB_FOUND)
set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES})
+4 -4
View File
@@ -254,6 +254,8 @@ void SConfig::SaveCoreSettings(IniFile& ini)
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
{
core->Set(StringFromFormat("SIDevice%i", i), m_SIDevice[i]);
core->Set(StringFromFormat("AdapterRumble%i", i), m_AdapterRumble[i]);
core->Set(StringFromFormat("SimulateKonga%i", i), m_AdapterKonga[i]);
}
core->Set("WiiSDCard", m_WiiSDCard);
core->Set("WiiKeyboard", m_WiiKeyboard);
@@ -267,8 +269,6 @@ void SConfig::SaveCoreSettings(IniFile& ini)
core->Set("OverclockEnable", m_OCEnable);
core->Set("GFXBackend", m_strVideoBackend);
core->Set("GPUDeterminismMode", m_strGPUDeterminismMode);
core->Set("GameCubeAdapter", m_GameCubeAdapter);
core->Set("AdapterRumble", m_AdapterRumble);
core->Set("PerfMapDir", m_perfDir);
}
@@ -509,6 +509,8 @@ void SConfig::LoadCoreSettings(IniFile& ini)
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
{
core->Get(StringFromFormat("SIDevice%i", i), (u32*)&m_SIDevice[i], (i == 0) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE);
core->Get(StringFromFormat("AdapterRumble%i", i), &m_AdapterRumble[i], true);
core->Get(StringFromFormat("SimulateKonga%i", i), &m_AdapterKonga[i], false);
}
core->Get("WiiSDCard", &m_WiiSDCard, false);
core->Get("WiiKeyboard", &m_WiiKeyboard, false);
@@ -532,8 +534,6 @@ void SConfig::LoadCoreSettings(IniFile& ini)
core->Get("FrameSkip", &m_FrameSkip, 0);
core->Get("GFXBackend", &m_strVideoBackend, "");
core->Get("GPUDeterminismMode", &m_strGPUDeterminismMode, "auto");
core->Get("GameCubeAdapter", &m_GameCubeAdapter, false);
core->Get("AdapterRumble", &m_AdapterRumble, true);
core->Get("PerfMapDir", &m_perfDir, "");
}
+2 -2
View File
@@ -264,8 +264,8 @@ struct SConfig : NonCopyable
// Input settings
bool m_BackgroundInput;
bool m_GameCubeAdapter;
bool m_AdapterRumble;
bool m_AdapterRumble[4];
bool m_AdapterKonga[4];
SysConf* m_SYSCONF;
+4 -6
View File
@@ -48,9 +48,6 @@
#include "Core/HW/HW.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/ProcessorInterface.h"
#if defined(__LIBUSB__) || defined(_WIN32)
#include "Core/HW/SI_GCAdapter.h"
#endif
#include "Core/HW/SystemTimers.h"
#include "Core/HW/VideoInterface.h"
#include "Core/HW/Wiimote.h"
@@ -65,6 +62,7 @@
#endif
#include "DiscIO/FileMonitor.h"
#include "InputCommon/GCAdapter.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/VideoBackendBase.h"
@@ -285,7 +283,7 @@ void Stop() // - Hammertime!
g_video_backend->Video_ExitLoop();
}
#if defined(__LIBUSB__) || defined(_WIN32)
SI_GCAdapter::ResetRumble();
GCAdapter::ResetRumble();
#endif
#ifdef USE_MEMORYWATCHER
@@ -630,7 +628,7 @@ void SetState(EState _State)
CPU::EnableStepping(true); // Break
Wiimote::Pause();
#if defined(__LIBUSB__) || defined(_WIN32)
SI_GCAdapter::ResetRumble();
GCAdapter::ResetRumble();
#endif
break;
case CORE_RUN:
@@ -741,7 +739,7 @@ bool PauseAndLock(bool doLock, bool unpauseOnUnlock)
g_video_backend->PauseAndLock(doLock, unpauseOnUnlock);
#if defined(__LIBUSB__) || defined(_WIN32)
SI_GCAdapter::ResetRumble();
GCAdapter::ResetRumble();
#endif
return wasUnpaused;
}
+2 -8
View File
@@ -145,16 +145,10 @@
<ClCompile Include="HW\SI_DeviceAMBaseboard.cpp" />
<ClCompile Include="HW\SI_DeviceDanceMat.cpp" />
<ClCompile Include="HW\SI_DeviceGBA.cpp" />
<ClCompile Include="HW\SI_DeviceGCAdapter.cpp" />
<ClCompile Include="HW\SI_DeviceGCController.cpp" />
<ClCompile Include="HW\SI_DeviceGCSteeringWheel.cpp" />
<ClCompile Include="HW\SI_DeviceKeyboard.cpp" />
<ClCompile Include="HW\SI_GCAdapter.cpp">
<!--
Disable "nonstandard extension used : zero-sized array in struct/union" warning,
which is hit in libusb.h.
-->
<DisableSpecificWarnings>4200;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ClCompile Include="HW\Sram.cpp" />
<ClCompile Include="HW\StreamADPCM.cpp" />
<ClCompile Include="HW\SystemTimers.cpp" />
@@ -357,10 +351,10 @@
<ClInclude Include="HW\SI_DeviceAMBaseboard.h" />
<ClInclude Include="HW\SI_DeviceDanceMat.h" />
<ClInclude Include="HW\SI_DeviceGBA.h" />
<ClInclude Include="HW\SI_DeviceGCAdapter.h" />
<ClInclude Include="HW\SI_DeviceGCController.h" />
<ClInclude Include="HW\SI_DeviceGCSteeringWheel.h" />
<ClInclude Include="HW\SI_DeviceKeyboard.h" />
<ClInclude Include="HW\SI_GCAdapter.h" />
<ClInclude Include="HW\Sram.h" />
<ClInclude Include="HW\StreamADPCM.h" />
<ClInclude Include="HW\SystemTimers.h" />
+6 -6
View File
@@ -447,6 +447,9 @@
<ClCompile Include="HW\SI_DeviceGBA.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
<ClCompile Include="HW\SI_DeviceGCAdapter.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
<ClCompile Include="HW\SI_DeviceGCController.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
@@ -720,9 +723,6 @@
<ClCompile Include="PowerPC\MMU.cpp">
<Filter>PowerPC</Filter>
</ClCompile>
<ClCompile Include="HW\SI_GCAdapter.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
<ClCompile Include="PowerPC\JitCommon\JitBackpatch.cpp">
<Filter>PowerPC\JitCommon</Filter>
</ClCompile>
@@ -991,6 +991,9 @@
<ClInclude Include="HW\SI_DeviceGBA.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
<ClInclude Include="HW\SI_DeviceGCAdapter.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
<ClInclude Include="HW\SI_DeviceGCController.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
@@ -1241,9 +1244,6 @@
<ClInclude Include="HW\GCKeyboard.h">
<Filter>HW %28Flipper/Hollywood%29\GCKeyboard</Filter>
</ClInclude>
<ClInclude Include="HW\SI_GCAdapter.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
<ClInclude Include="PowerPC\Jit64Common\Jit64AsmCommon.h">
<Filter>PowerPC\Jit64Common</Filter>
</ClInclude>
+4
View File
@@ -11,6 +11,7 @@
#include "Core/HW/SI_DeviceAMBaseboard.h"
#include "Core/HW/SI_DeviceDanceMat.h"
#include "Core/HW/SI_DeviceGBA.h"
#include "Core/HW/SI_DeviceGCAdapter.h"
#include "Core/HW/SI_DeviceGCController.h"
#include "Core/HW/SI_DeviceGCSteeringWheel.h"
#include "Core/HW/SI_DeviceKeyboard.h"
@@ -73,6 +74,9 @@ std::unique_ptr<ISIDevice> SIDevice_Create(const SIDevices device, const int por
case SIDEVICE_GC_CONTROLLER:
return std::make_unique<CSIDevice_GCController>(device, port_number);
case SIDEVICE_WIIU_ADAPTER:
return std::make_unique<CSIDevice_GCAdapter>(device, port_number);
case SIDEVICE_DANCEMAT:
return std::make_unique<CSIDevice_DanceMat>(device, port_number);
+2 -1
View File
@@ -61,7 +61,8 @@ enum SIDevices : int
SIDEVICE_GC_STEERING,
SIDEVICE_DANCEMAT,
SIDEVICE_GC_TARUKONGA,
SIDEVICE_AM_BASEBOARD
SIDEVICE_AM_BASEBOARD,
SIDEVICE_WIIU_ADAPTER,
};
+150
View File
@@ -0,0 +1,150 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/MsgHandler.h"
#include "Common/Logging/Log.h"
#include "Core/ConfigManager.h"
#include "Core/Movie.h"
#include "Core/HW/SI_DeviceGCAdapter.h"
CSIDevice_GCAdapter::CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber)
: CSIDevice_GCController(device, _iDeviceNumber)
{
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
m_simulate_konga = SConfig::GetInstance().m_AdapterKonga[numPAD];
}
GCPadStatus CSIDevice_GCAdapter::GetPadStatus()
{
GCPadStatus PadStatus;
memset(&PadStatus, 0, sizeof(PadStatus));
GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus);
HandleMoviePadStatus(&PadStatus);
return PadStatus;
}
int CSIDevice_GCAdapter::RunBuffer(u8* _pBuffer, int _iLength)
{
// For debug logging only
ISIDevice::RunBuffer(_pBuffer, _iLength);
// Read the command
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (!GCAdapter::DeviceConnected(numPAD))
{
reinterpret_cast<u32*>(_pBuffer)[0] = SI_NONE;
return 4;
}
// Handle it
switch (command)
{
case CMD_RESET:
case CMD_ID:
*(u32*)&_pBuffer[0] = SI_GC_CONTROLLER;
break;
case CMD_DIRECT:
{
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength);
u32 high, low;
GetData(high, low);
for (int i = 0; i < (_iLength - 1) / 2; i++)
{
_pBuffer[i + 0] = (high >> (i * 8)) & 0xff;
_pBuffer[i + 4] = (low >> (i * 8)) & 0xff;
}
}
break;
case CMD_ORIGIN:
{
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
Calibrate();
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// Recalibrate (FiRES: i am not 100 percent sure about this)
case CMD_RECALIBRATE:
{
INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
Calibrate();
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// DEFAULT
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
PanicAlert("SI: Unknown command (0x%x)", command);
}
break;
}
return _iLength;
}
void CSIDevice_GCAdapter::SendCommand(u32 _Cmd, u8 _Poll)
{
UCommand command(_Cmd);
switch (command.Command)
{
// Costis sent it in some demos :)
case 0x00:
break;
case CMD_WRITE:
{
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
unsigned int uStrength = command.Parameter2;
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
{
if (uType == 1 && uStrength > 2)
GCAdapter::Output(numPAD, 1);
else
GCAdapter::Output(numPAD, 0);
}
if (!_Poll)
{
m_Mode = command.Parameter2;
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
}
}
break;
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
PanicAlert("SI: Unknown direct command");
}
break;
}
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Core/HW/SI_Device.h"
#include "Core/HW/SI_DeviceGCController.h"
#include "InputCommon/GCAdapter.h"
#include "InputCommon/GCPadStatus.h"
class CSIDevice_GCAdapter : public CSIDevice_GCController
{
public:
CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber);
GCPadStatus GetPadStatus() override;
int RunBuffer(u8* _pBuffer, int _iLength) override;
void SendCommand(u32 _Cmd, u8 _Poll) override;
};
+37 -39
View File
@@ -13,9 +13,6 @@
#include "Core/HW/SI.h"
#include "Core/HW/SI_Device.h"
#include "Core/HW/SI_DeviceGCController.h"
#if defined(__LIBUSB__) || defined (_WIN32)
#include "Core/HW/SI_GCAdapter.h"
#endif
#include "Core/HW/SystemTimers.h"
#include "InputCommon/GCPadStatus.h"
@@ -119,6 +116,30 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
return _iLength;
}
void CSIDevice_GCController::HandleMoviePadStatus(GCPadStatus* PadStatus)
{
Movie::CallGCInputManip(PadStatus, ISIDevice::m_iDeviceNumber);
Movie::SetPolledDevice();
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus))
{
}
else if (Movie::IsPlayingInput())
{
Movie::PlayController(PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else if (Movie::IsRecordingInput())
{
Movie::RecordInput(PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else
{
Movie::CheckPadStatus(PadStatus, ISIDevice::m_iDeviceNumber);
}
}
GCPadStatus CSIDevice_GCController::GetPadStatus()
{
GCPadStatus PadStatus;
@@ -126,31 +147,7 @@ GCPadStatus CSIDevice_GCController::GetPadStatus()
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
#if defined(__LIBUSB__) || defined (_WIN32)
SI_GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus);
#endif
Movie::CallGCInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::SetPolledDevice();
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, &PadStatus))
{
}
else if (Movie::IsPlayingInput())
{
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else if (Movie::IsRecordingInput())
{
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else
{
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
}
HandleMoviePadStatus(&PadStatus);
return PadStatus;
}
@@ -163,6 +160,8 @@ GCPadStatus CSIDevice_GCController::GetPadStatus()
bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
{
GCPadStatus PadStatus = GetPadStatus();
if (HandleButtonCombos(PadStatus) == COMBO_ORIGIN)
PadStatus.button |= PAD_GET_ORIGIN;
_Hi = MapPadStatus(PadStatus);
@@ -211,7 +210,12 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
HandleButtonCombos(PadStatus);
// Unset all bits except those that represent
// A, B, X, Y, Start and the error bits, as they
// are not used.
if (m_simulate_konga)
_Hi &= ~0x20FFFFFF;
return true;
}
@@ -225,7 +229,7 @@ u32 CSIDevice_GCController::MapPadStatus(const GCPadStatus& pad_status)
return _Hi;
}
void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
CSIDevice_GCController::EButtonCombo CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
{
// Keep track of the special button combos (embedded in controller hardware... :( )
EButtonCombo tempCombo;
@@ -258,8 +262,11 @@ void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
m_Origin.uTrigger_R = pad_status.triggerRight;
}
m_LastButtonCombo = COMBO_NONE;
return tempCombo;
}
}
return COMBO_NONE;
}
// SendCommand
@@ -281,15 +288,6 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
#if defined(__LIBUSB__) || defined (_WIN32)
if (numPAD < 4)
{
if (uType == 1 && uStrength > 2)
SI_GCAdapter::Output(numPAD, 1);
else
SI_GCAdapter::Output(numPAD, 0);
}
#endif
if (numPAD < 4)
{
if (uType == 1 && uStrength > 2)
+8 -12
View File
@@ -79,6 +79,9 @@ protected:
// Type of button combo from the last/current poll
EButtonCombo m_LastButtonCombo;
// Set this if we want to simulate the "TaruKonga" DK Bongo controller
bool m_simulate_konga = false;
public:
// Constructor
@@ -98,14 +101,15 @@ public:
virtual GCPadStatus GetPadStatus();
virtual u32 MapPadStatus(const GCPadStatus& pad_status);
virtual void HandleButtonCombos(const GCPadStatus& pad_status);
virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status);
// Send and Receive pad input from network
static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status);
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
private:
protected:
void Calibrate();
void HandleMoviePadStatus(GCPadStatus* PadStatus);
};
@@ -113,16 +117,8 @@ private:
class CSIDevice_TaruKonga : public CSIDevice_GCController
{
public:
CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) : CSIDevice_GCController(device, _iDeviceNumber) { }
bool GetData(u32& _Hi, u32& _Low) override
CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) : CSIDevice_GCController(device, _iDeviceNumber)
{
CSIDevice_GCController::GetData(_Hi, _Low);
// Unset all bits except those that represent
// A, B, X, Y, Start and the error bits, as they
// are not used.
_Hi &= ~0x20FFFFFF;
return true;
m_simulate_konga = true;
}
};
-461
View File
@@ -1,461 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <libusb.h>
#include <mutex>
#include "Common/Flag.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/SI.h"
#include "Core/HW/SI_GCAdapter.h"
#include "Core/HW/SystemTimers.h"
#include "InputCommon/GCPadStatus.h"
namespace SI_GCAdapter
{
enum ControllerTypes
{
CONTROLLER_NONE = 0,
CONTROLLER_WIRED = 1,
CONTROLLER_WIRELESS = 2
};
static bool CheckDeviceAccess(libusb_device* device);
static void AddGCAdapter(libusb_device* device);
static bool s_detected = false;
static libusb_device_handle* s_handle = nullptr;
static u8 s_controller_type[MAX_SI_CHANNELS] = { CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE };
static u8 s_controller_rumble[4];
static std::mutex s_mutex;
static u8 s_controller_payload[37];
static u8 s_controller_payload_swap[37];
static int s_controller_payload_size = 0;
static std::thread s_adapter_thread;
static Common::Flag s_adapter_thread_running;
static std::thread s_adapter_detect_thread;
static Common::Flag s_adapter_detect_thread_running;
static std::function<void(void)> s_detect_callback;
static bool s_libusb_driver_not_supported = false;
static libusb_context* s_libusb_context = nullptr;
static bool s_libusb_hotplug_enabled = false;
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
static libusb_hotplug_callback_handle s_hotplug_handle;
#endif
static u8 s_endpoint_in = 0;
static u8 s_endpoint_out = 0;
static u64 s_last_init = 0;
static void Read()
{
while (s_adapter_thread_running.IsSet())
{
libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap, sizeof(s_controller_payload_swap), &s_controller_payload_size, 16);
{
std::lock_guard<std::mutex> lk(s_mutex);
std::swap(s_controller_payload_swap, s_controller_payload);
}
Common::YieldCPU();
}
}
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotplug_event event, void* user_data)
{
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
{
if (s_handle == nullptr && CheckDeviceAccess(dev))
AddGCAdapter(dev);
}
else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
{
if (s_handle != nullptr && libusb_get_device(s_handle) == dev)
Reset();
}
return 0;
}
#endif
static void ScanThreadFunc()
{
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started");
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
s_libusb_hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0;
if (s_libusb_hotplug_enabled)
{
if (libusb_hotplug_register_callback(s_libusb_context, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS)
s_libusb_hotplug_enabled = false;
if (s_libusb_hotplug_enabled)
NOTICE_LOG(SERIALINTERFACE, "Using libUSB hotplug detection");
}
#endif
while (s_adapter_detect_thread_running.IsSet())
{
if (s_libusb_hotplug_enabled)
{
static timeval tv = {0, 500000};
libusb_handle_events_timeout(s_libusb_context, &tv);
}
else
{
if (s_handle == nullptr)
{
Setup();
if (s_detected && s_detect_callback != nullptr)
s_detect_callback();
}
Common::SleepCurrentThread(500);
}
}
NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped");
}
void SetAdapterCallback(std::function<void(void)> func)
{
s_detect_callback = func;
}
void Init()
{
if (s_handle != nullptr)
return;
if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond())
return;
s_last_init = CoreTiming::GetTicks();
}
s_libusb_driver_not_supported = false;
int ret = libusb_init(&s_libusb_context);
if (ret)
{
ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret);
s_libusb_driver_not_supported = true;
Shutdown();
}
else
{
if (SConfig::GetInstance().m_GameCubeAdapter)
StartScanThread();
}
}
void StartScanThread()
{
s_adapter_detect_thread_running.Set(true);
s_adapter_detect_thread = std::thread(ScanThreadFunc);
}
void StopScanThread()
{
if (s_adapter_detect_thread_running.TestAndClear())
{
s_adapter_detect_thread.join();
}
}
void Setup()
{
libusb_device** list;
ssize_t cnt = libusb_get_device_list(s_libusb_context, &list);
for (int i = 0; i < MAX_SI_CHANNELS; i++)
{
s_controller_type[i] = CONTROLLER_NONE;
s_controller_rumble[i] = 0;
}
for (int d = 0; d < cnt; d++)
{
libusb_device* device = list[d];
if (CheckDeviceAccess(device))
AddGCAdapter(device);
}
libusb_free_device_list(list, 1);
}
static bool CheckDeviceAccess(libusb_device* device)
{
int ret;
libusb_device_descriptor desc;
int dRet = libusb_get_device_descriptor(device, &desc);
if (dRet)
{
// could not acquire the descriptor, no point in trying to use it.
ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet);
return false;
}
if (desc.idVendor == 0x057e && desc.idProduct == 0x0337)
{
NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, 1);
u8 bus = libusb_get_bus_number(device);
u8 port = libusb_get_device_address(device);
ret = libusb_open(device, &s_handle);
if (ret)
{
if (ret == LIBUSB_ERROR_ACCESS)
{
if (dRet)
{
ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).",
bus,
port
);
}
else
{
ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.",
bus,
port,
desc.idVendor,
desc.idProduct
);
}
}
else
{
ERROR_LOG(SERIALINTERFACE, "libusb_open failed to open device with error = %d", ret);
if (ret == LIBUSB_ERROR_NOT_SUPPORTED)
s_libusb_driver_not_supported = true;
}
return false;
}
else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1)
{
if ((ret = libusb_detach_kernel_driver(s_handle, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED)
{
ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret);
}
}
// this split is needed so that we don't avoid claiming the interface when
// detaching the kernel driver is successful
if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
{
return false;
}
else if ((ret = libusb_claim_interface(s_handle, 0)))
{
ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret);
}
else
{
return true;
}
}
return false;
}
static void AddGCAdapter(libusb_device* device)
{
libusb_config_descriptor *config = nullptr;
libusb_get_config_descriptor(device, 0, &config);
for (u8 ic = 0; ic < config->bNumInterfaces; ic++)
{
const libusb_interface *interfaceContainer = &config->interface[ic];
for (int i = 0; i < interfaceContainer->num_altsetting; i++)
{
const libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i];
for (u8 e = 0; e < interface->bNumEndpoints; e++)
{
const libusb_endpoint_descriptor *endpoint = &interface->endpoint[e];
if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN)
s_endpoint_in = endpoint->bEndpointAddress;
else
s_endpoint_out = endpoint->bEndpointAddress;
}
}
}
int tmp = 0;
unsigned char payload = 0x13;
libusb_interrupt_transfer(s_handle, s_endpoint_out, &payload, sizeof(payload), &tmp, 16);
s_adapter_thread_running.Set(true);
s_adapter_thread = std::thread(Read);
s_detected = true;
if (s_detect_callback != nullptr)
s_detect_callback();
ResetRumble();
}
void Shutdown()
{
StopScanThread();
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
if (s_libusb_hotplug_enabled)
libusb_hotplug_deregister_callback(s_libusb_context, s_hotplug_handle);
#endif
Reset();
if (s_libusb_context)
{
libusb_exit(s_libusb_context);
s_libusb_context = nullptr;
}
s_libusb_driver_not_supported = false;
}
void Reset()
{
if (!s_detected)
return;
if (s_adapter_thread_running.TestAndClear())
{
s_adapter_thread.join();
}
for (int i = 0; i < MAX_SI_CHANNELS; i++)
s_controller_type[i] = CONTROLLER_NONE;
s_detected = false;
if (s_handle)
{
libusb_release_interface(s_handle, 0);
libusb_close(s_handle);
s_handle = nullptr;
}
if (s_detect_callback != nullptr)
s_detect_callback();
NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached");
}
void Input(int chan, GCPadStatus* pad)
{
if (!SConfig::GetInstance().m_GameCubeAdapter)
return;
if (s_handle == nullptr || !s_detected)
return;
u8 controller_payload_copy[37];
{
std::lock_guard<std::mutex> lk(s_mutex);
std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), std::begin(controller_payload_copy));
}
if (s_controller_payload_size != sizeof(controller_payload_copy) || controller_payload_copy[0] != LIBUSB_DT_HID)
{
INFO_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", s_controller_payload_size, controller_payload_copy[0]);
Reset();
}
else
{
u8 type = controller_payload_copy[1 + (9 * chan)] >> 4;
if (type != CONTROLLER_NONE && s_controller_type[chan] == CONTROLLER_NONE)
NOTICE_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, controller_payload_copy[1 + (9 * chan)]);
s_controller_type[chan] = type;
if (s_controller_type[chan] != CONTROLLER_NONE)
{
memset(pad, 0, sizeof(*pad));
u8 b1 = controller_payload_copy[1 + (9 * chan) + 1];
u8 b2 = controller_payload_copy[1 + (9 * chan) + 2];
if (b1 & (1 << 0)) pad->button |= PAD_BUTTON_A;
if (b1 & (1 << 1)) pad->button |= PAD_BUTTON_B;
if (b1 & (1 << 2)) pad->button |= PAD_BUTTON_X;
if (b1 & (1 << 3)) pad->button |= PAD_BUTTON_Y;
if (b1 & (1 << 4)) pad->button |= PAD_BUTTON_LEFT;
if (b1 & (1 << 5)) pad->button |= PAD_BUTTON_RIGHT;
if (b1 & (1 << 6)) pad->button |= PAD_BUTTON_DOWN;
if (b1 & (1 << 7)) pad->button |= PAD_BUTTON_UP;
if (b2 & (1 << 0)) pad->button |= PAD_BUTTON_START;
if (b2 & (1 << 1)) pad->button |= PAD_TRIGGER_Z;
if (b2 & (1 << 2)) pad->button |= PAD_TRIGGER_R;
if (b2 & (1 << 3)) pad->button |= PAD_TRIGGER_L;
pad->stickX = controller_payload_copy[1 + (9 * chan) + 3];
pad->stickY = controller_payload_copy[1 + (9 * chan) + 4];
pad->substickX = controller_payload_copy[1 + (9 * chan) + 5];
pad->substickY = controller_payload_copy[1 + (9 * chan) + 6];
pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7];
pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8];
}
}
}
void ResetRumble()
{
if (!SConfig::GetInstance().m_GameCubeAdapter)
return;
if (s_handle == nullptr || !s_detected)
return;
std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0);
unsigned char rumble[5] = {0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3]};
int size = 0;
libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16);
DEBUG_LOG(SERIALINTERFACE, "Rumble state reset");
}
void Output(int chan, u8 rumble_command)
{
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter || !SConfig::GetInstance().m_AdapterRumble)
return;
// Skip over rumble commands if it has not changed or the controller is wireless
if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != CONTROLLER_WIRELESS)
{
s_controller_rumble[chan] = rumble_command;
unsigned char rumble[5] = { 0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3] };
int size = 0;
libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16);
// Netplay sends invalid data which results in size = 0x00. Ignore it.
if (size != 0x05 && size != 0x00)
{
INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size);
Reset();
}
}
}
bool IsDetected()
{
return s_detected;
}
bool IsDriverDetected()
{
return !s_libusb_driver_not_supported;
}
} // end of namespace SI_GCAdapter
-27
View File
@@ -1,27 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
struct GCPadStatus;
namespace SI_GCAdapter
{
void Init();
void Reset();
void ResetRumble();
void Setup();
void Shutdown();
void SetAdapterCallback(std::function<void(void)> func);
void StartScanThread();
void StopScanThread();
void Input(int chan, GCPadStatus* pad);
void Output(int chan, u8 rumble_command);
bool IsDetected();
bool IsDriverDetected();
} // end of namespace SI_GCAdapter