mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Merge pull request #1678 from skidau/GC-Adapter
Added GameCube Adapter support
This commit is contained in:
@ -247,7 +247,8 @@ set(LIBS
|
|||||||
if(LIBUSB_FOUND)
|
if(LIBUSB_FOUND)
|
||||||
# Using shared LibUSB
|
# Using shared LibUSB
|
||||||
set(LIBS ${LIBS} ${LIBUSB_LIBRARIES})
|
set(LIBS ${LIBS} ${LIBUSB_LIBRARIES})
|
||||||
set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp)
|
set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp
|
||||||
|
HW/SI_GCAdapter.cpp)
|
||||||
endif(LIBUSB_FOUND)
|
endif(LIBUSB_FOUND)
|
||||||
|
|
||||||
set(LIBS ${LIBS} ${POLARSSL_LIBRARY})
|
set(LIBS ${LIBS} ${POLARSSL_LIBRARY})
|
||||||
|
@ -341,6 +341,7 @@ void SConfig::SaveCoreSettings(IniFile& ini)
|
|||||||
core->Set("FrameSkip", m_FrameSkip);
|
core->Set("FrameSkip", m_FrameSkip);
|
||||||
core->Set("GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend);
|
core->Set("GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend);
|
||||||
core->Set("GPUDeterminismMode", m_LocalCoreStartupParameter.m_strGPUDeterminismMode);
|
core->Set("GPUDeterminismMode", m_LocalCoreStartupParameter.m_strGPUDeterminismMode);
|
||||||
|
core->Set("GameCubeAdapter", m_GameCubeAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConfig::SaveMovieSettings(IniFile& ini)
|
void SConfig::SaveMovieSettings(IniFile& ini)
|
||||||
@ -574,6 +575,7 @@ void SConfig::LoadCoreSettings(IniFile& ini)
|
|||||||
core->Get("FrameSkip", &m_FrameSkip, 0);
|
core->Get("FrameSkip", &m_FrameSkip, 0);
|
||||||
core->Get("GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");
|
core->Get("GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");
|
||||||
core->Get("GPUDeterminismMode", &m_LocalCoreStartupParameter.m_strGPUDeterminismMode, "auto");
|
core->Get("GPUDeterminismMode", &m_LocalCoreStartupParameter.m_strGPUDeterminismMode, "auto");
|
||||||
|
core->Get("GameCubeAdapter", &m_GameCubeAdapter, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConfig::LoadMovieSettings(IniFile& ini)
|
void SConfig::LoadMovieSettings(IniFile& ini)
|
||||||
|
@ -107,6 +107,7 @@ struct SConfig : NonCopyable
|
|||||||
|
|
||||||
// Input settings
|
// Input settings
|
||||||
bool m_BackgroundInput;
|
bool m_BackgroundInput;
|
||||||
|
bool m_GameCubeAdapter;
|
||||||
|
|
||||||
SysConf* m_SYSCONF;
|
SysConf* m_SYSCONF;
|
||||||
|
|
||||||
|
@ -147,6 +147,13 @@
|
|||||||
<ClCompile Include="HW\SI_DeviceGBA.cpp" />
|
<ClCompile Include="HW\SI_DeviceGBA.cpp" />
|
||||||
<ClCompile Include="HW\SI_DeviceGCController.cpp" />
|
<ClCompile Include="HW\SI_DeviceGCController.cpp" />
|
||||||
<ClCompile Include="HW\SI_DeviceGCSteeringWheel.cpp" />
|
<ClCompile Include="HW\SI_DeviceGCSteeringWheel.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\Sram.cpp" />
|
||||||
<ClCompile Include="HW\StreamADPCM.cpp" />
|
<ClCompile Include="HW\StreamADPCM.cpp" />
|
||||||
<ClCompile Include="HW\SystemTimers.cpp" />
|
<ClCompile Include="HW\SystemTimers.cpp" />
|
||||||
@ -176,7 +183,7 @@
|
|||||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_hid.cpp">
|
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_hid.cpp">
|
||||||
<!--
|
<!--
|
||||||
Disable "nonstandard extension used : zero-sized array in struct/union" warning,
|
Disable "nonstandard extension used : zero-sized array in struct/union" warning,
|
||||||
which is hit in libusb.h (and this is the only file which uses that header).
|
which is hit in libusb.h.
|
||||||
-->
|
-->
|
||||||
<DisableSpecificWarnings>4200;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4200;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -345,6 +352,7 @@
|
|||||||
<ClInclude Include="HW\SI_DeviceGBA.h" />
|
<ClInclude Include="HW\SI_DeviceGBA.h" />
|
||||||
<ClInclude Include="HW\SI_DeviceGCController.h" />
|
<ClInclude Include="HW\SI_DeviceGCController.h" />
|
||||||
<ClInclude Include="HW\SI_DeviceGCSteeringWheel.h" />
|
<ClInclude Include="HW\SI_DeviceGCSteeringWheel.h" />
|
||||||
|
<ClInclude Include="HW\SI_GCAdapter.h" />
|
||||||
<ClInclude Include="HW\Sram.h" />
|
<ClInclude Include="HW\Sram.h" />
|
||||||
<ClInclude Include="HW\StreamADPCM.h" />
|
<ClInclude Include="HW\StreamADPCM.h" />
|
||||||
<ClInclude Include="HW\SystemTimers.h" />
|
<ClInclude Include="HW\SystemTimers.h" />
|
||||||
|
@ -473,22 +473,30 @@ static void SetNoResponse(u32 channel)
|
|||||||
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
u8 channel = (u8)(userdata >> 32);
|
u8 channel = (u8)(userdata >> 32);
|
||||||
|
SIDevices device = (SIDevices)(u32)userdata;
|
||||||
|
|
||||||
g_Channel[channel].m_Out.Hex = 0;
|
// Skip redundant (spammed) device changes
|
||||||
g_Channel[channel].m_InHi.Hex = 0;
|
if (GetDeviceType(channel) != device)
|
||||||
g_Channel[channel].m_InLo.Hex = 0;
|
{
|
||||||
|
g_Channel[channel].m_Out.Hex = 0;
|
||||||
|
g_Channel[channel].m_InHi.Hex = 0;
|
||||||
|
g_Channel[channel].m_InLo.Hex = 0;
|
||||||
|
|
||||||
SetNoResponse(channel);
|
SetNoResponse(channel);
|
||||||
|
|
||||||
AddDevice((SIDevices)(u32)userdata, channel);
|
AddDevice(device, channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeDevice(SIDevices device, int channel)
|
void ChangeDevice(SIDevices device, int channel)
|
||||||
{
|
{
|
||||||
// Called from GUI, so we need to make it thread safe.
|
// Called from GUI, so we need to make it thread safe.
|
||||||
// Let the hardware see no device for .5b cycles
|
// Let the hardware see no device for .5b cycles
|
||||||
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE);
|
if (GetDeviceType(channel) != device)
|
||||||
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device);
|
{
|
||||||
|
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE);
|
||||||
|
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDevices()
|
void UpdateDevices()
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include "Core/HW/SI.h"
|
#include "Core/HW/SI.h"
|
||||||
#include "Core/HW/SI_Device.h"
|
#include "Core/HW/SI_Device.h"
|
||||||
#include "Core/HW/SI_DeviceGCController.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 "Core/HW/SystemTimers.h"
|
||||||
|
|
||||||
// --- standard GameCube controller ---
|
// --- standard GameCube controller ---
|
||||||
@ -110,6 +113,11 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
|||||||
memset(&PadStatus, 0, sizeof(PadStatus));
|
memset(&PadStatus, 0, sizeof(PadStatus));
|
||||||
|
|
||||||
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
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::CallGCInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||||
|
|
||||||
Movie::SetPolledDevice();
|
Movie::SetPolledDevice();
|
||||||
@ -248,6 +256,9 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
|
|||||||
// get the correct pad number that should rumble locally when using netplay
|
// get the correct pad number that should rumble locally when using netplay
|
||||||
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
||||||
|
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
SI_GCAdapter::Output(numPAD, command.Parameter1 & 0xff);
|
||||||
|
#endif
|
||||||
if (numPAD < 4)
|
if (numPAD < 4)
|
||||||
{
|
{
|
||||||
if (uType == 1 && uStrength > 2)
|
if (uType == 1 && uStrength > 2)
|
||||||
|
319
Source/Core/Core/HW/SI_GCAdapter.cpp
Normal file
319
Source/Core/Core/HW/SI_GCAdapter.cpp
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
|
#include "Core/HW/SI_GCAdapter.h"
|
||||||
|
|
||||||
|
namespace SI_GCAdapter
|
||||||
|
{
|
||||||
|
enum ControllerTypes
|
||||||
|
{
|
||||||
|
CONTROLLER_NONE = 0,
|
||||||
|
CONTROLLER_WIRED = 1,
|
||||||
|
CONTROLLER_WIRELESS = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
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 int s_controller_payload_size = 0;
|
||||||
|
|
||||||
|
static std::thread s_adapter_thread;
|
||||||
|
static Common::Flag s_adapter_thread_running;
|
||||||
|
|
||||||
|
static bool s_libusb_driver_not_supported = false;
|
||||||
|
|
||||||
|
static u8 s_endpoint_in = 0;
|
||||||
|
static u8 s_endpoint_out = 0;
|
||||||
|
|
||||||
|
void Read()
|
||||||
|
{
|
||||||
|
while (s_adapter_thread_running.IsSet())
|
||||||
|
{
|
||||||
|
u8 controller_payload_swap[37];
|
||||||
|
|
||||||
|
libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload, sizeof(controller_payload_swap), &s_controller_payload_size, 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(s_mutex);
|
||||||
|
std::swap(controller_payload_swap, s_controller_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::YieldCPU();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
if (s_handle != nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_libusb_driver_not_supported = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_SI_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
s_controller_type[i] = CONTROLLER_NONE;
|
||||||
|
s_controller_rumble[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = libusb_init(nullptr);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
libusb_device** list;
|
||||||
|
ssize_t cnt = libusb_get_device_list(nullptr, &list);
|
||||||
|
for (int d = 0; d < cnt; d++)
|
||||||
|
{
|
||||||
|
libusb_device* device = list[d];
|
||||||
|
libusb_device_descriptor desc;
|
||||||
|
int dRet = libusb_get_device_descriptor(device, &desc);
|
||||||
|
if (dRet)
|
||||||
|
{
|
||||||
|
// could not aquire the descriptor, no point in trying to use it.
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
|
||||||
|
{
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "libusb_kernel_driver_active error ret = %d", ret);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
else if ((ret = libusb_claim_interface(s_handle, 0)))
|
||||||
|
{
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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 (int e = 0; e < (int)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, 0);
|
||||||
|
|
||||||
|
RefreshConnectedDevices();
|
||||||
|
|
||||||
|
s_adapter_thread_running.Set(true);
|
||||||
|
s_adapter_thread = std::thread(Read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_free_device_list(list, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown()
|
||||||
|
{
|
||||||
|
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (s_adapter_thread_running.TestAndClear())
|
||||||
|
{
|
||||||
|
s_adapter_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_close(s_handle);
|
||||||
|
s_libusb_driver_not_supported = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_SI_CHANNELS; i++)
|
||||||
|
s_controller_type[i] = CONTROLLER_NONE;
|
||||||
|
|
||||||
|
s_handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input(int chan, GCPadStatus* pad)
|
||||||
|
{
|
||||||
|
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d)", s_controller_payload_size);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
pad->button = controller_payload_copy[1 + (9 * chan) + 1] << 8;
|
||||||
|
|
||||||
|
u8 b = controller_payload_copy[1 + (9 * chan) + 2];
|
||||||
|
if (b & (1 << 0)) pad->button |= PAD_BUTTON_START;
|
||||||
|
if (b & (1 << 1)) pad->button |= PAD_TRIGGER_Z;
|
||||||
|
if (b & (1 << 2)) pad->button |= PAD_TRIGGER_R;
|
||||||
|
if (b & (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 Output(int chan, u8 rumble)
|
||||||
|
{
|
||||||
|
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Skip over rumble commands if it has not changed or the controller is wireless
|
||||||
|
if (rumble != s_controller_rumble[chan] && s_controller_type[chan] != CONTROLLER_WIRELESS)
|
||||||
|
{
|
||||||
|
s_controller_rumble[chan] = rumble;
|
||||||
|
|
||||||
|
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, 0);
|
||||||
|
|
||||||
|
if (size != 0x05)
|
||||||
|
{
|
||||||
|
WARN_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SIDevices GetDeviceType(int channel)
|
||||||
|
{
|
||||||
|
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
|
||||||
|
return SIDEVICE_NONE;
|
||||||
|
|
||||||
|
switch (s_controller_type[channel])
|
||||||
|
{
|
||||||
|
case CONTROLLER_WIRED:
|
||||||
|
return SIDEVICE_GC_CONTROLLER;
|
||||||
|
case CONTROLLER_WIRELESS:
|
||||||
|
return SIDEVICE_GC_CONTROLLER;
|
||||||
|
default:
|
||||||
|
return SIDEVICE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshConnectedDevices()
|
||||||
|
{
|
||||||
|
if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
u8 refresh_controller_payload[37];
|
||||||
|
|
||||||
|
libusb_interrupt_transfer(s_handle, s_endpoint_in, refresh_controller_payload, sizeof(refresh_controller_payload), &size, 0);
|
||||||
|
|
||||||
|
if (size != sizeof(refresh_controller_payload) || refresh_controller_payload[0] != LIBUSB_DT_HID)
|
||||||
|
{
|
||||||
|
WARN_LOG(SERIALINTERFACE, "error reading payload (size: %d)", size);
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int chan = 0; chan < MAX_SI_CHANNELS; chan++)
|
||||||
|
{
|
||||||
|
u8 type = refresh_controller_payload[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, refresh_controller_payload[1 + (9 * chan)]);
|
||||||
|
|
||||||
|
s_controller_type[chan] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDetected()
|
||||||
|
{
|
||||||
|
return s_handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDriverDetected()
|
||||||
|
{
|
||||||
|
return !s_libusb_driver_not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace SI_GCAdapter
|
23
Source/Core/Core/HW/SI_GCAdapter.h
Normal file
23
Source/Core/Core/HW/SI_GCAdapter.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2013 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common/Thread.h"
|
||||||
|
#include "Core/HW/SI.h"
|
||||||
|
#include "InputCommon/GCPadStatus.h"
|
||||||
|
|
||||||
|
namespace SI_GCAdapter
|
||||||
|
{
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
void Input(int chan, GCPadStatus* pad);
|
||||||
|
void Output(int chan, u8 rumble);
|
||||||
|
SIDevices GetDeviceType(int channel);
|
||||||
|
void RefreshConnectedDevices();
|
||||||
|
bool IsDetected();
|
||||||
|
bool IsDriverDetected();
|
||||||
|
|
||||||
|
} // end of namespace SI_GCAdapter
|
@ -27,6 +27,9 @@
|
|||||||
#include "Core/NetPlayProto.h"
|
#include "Core/NetPlayProto.h"
|
||||||
#include "Core/HW/GCPad.h"
|
#include "Core/HW/GCPad.h"
|
||||||
#include "Core/HW/SI.h"
|
#include "Core/HW/SI.h"
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
#include "Core/HW/SI_GCAdapter.h"
|
||||||
|
#endif
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||||
#include "DolphinWX/ControllerConfigDiag.h"
|
#include "DolphinWX/ControllerConfigDiag.h"
|
||||||
@ -68,7 +71,7 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
|
|||||||
|
|
||||||
wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
|
wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
|
||||||
{
|
{
|
||||||
wxStaticBoxSizer* const gamecube_static_sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("GameCube Controllers"));
|
wxStaticBoxSizer* const gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
|
||||||
wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5);
|
wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5);
|
||||||
|
|
||||||
wxStaticText* pad_labels[4];
|
wxStaticText* pad_labels[4];
|
||||||
@ -134,6 +137,36 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5);
|
gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5);
|
||||||
|
gamecube_static_sizer->AddSpacer(5);
|
||||||
|
|
||||||
|
wxStaticBoxSizer* const gamecube_adapter_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("GameCube Adapter"));
|
||||||
|
wxBoxSizer* const gamecube_adapter_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
|
wxCheckBox* const gamecube_adapter = new wxCheckBox(this, wxID_ANY, _("Direct Connect"));
|
||||||
|
gamecube_adapter->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnGameCubeAdapter, this);
|
||||||
|
|
||||||
|
gamecube_adapter_sizer->Add(gamecube_adapter, 0, wxEXPAND);
|
||||||
|
gamecube_adapter_group->Add(gamecube_adapter_sizer, 0, wxEXPAND);
|
||||||
|
gamecube_static_sizer->Add(gamecube_adapter_group, 0, wxEXPAND);
|
||||||
|
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
if (!SI_GCAdapter::IsDetected())
|
||||||
|
{
|
||||||
|
if (!SI_GCAdapter::IsDriverDetected())
|
||||||
|
gamecube_adapter->SetLabelText(_("Driver Not Detected"));
|
||||||
|
else
|
||||||
|
gamecube_adapter->SetLabelText(_("Adapter Not Detected"));
|
||||||
|
gamecube_adapter->SetValue(false);
|
||||||
|
gamecube_adapter->Disable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gamecube_adapter->SetValue(SConfig::GetInstance().m_GameCubeAdapter);
|
||||||
|
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||||
|
gamecube_adapter->Disable();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return gamecube_static_sizer;
|
return gamecube_static_sizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,11 @@ public:
|
|||||||
SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked();
|
SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked();
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
void OnGameCubeAdapter(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
SConfig::GetInstance().m_GameCubeAdapter = event.IsChecked();
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxStaticBoxSizer* CreateGamecubeSizer();
|
wxStaticBoxSizer* CreateGamecubeSizer();
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#include "Common/Logging/LogManager.h"
|
#include "Common/Logging/LogManager.h"
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
#include "Core/HW/SI_GCAdapter.h"
|
||||||
|
#endif
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
|
|
||||||
#include "UICommon/UICommon.h"
|
#include "UICommon/UICommon.h"
|
||||||
@ -22,7 +25,9 @@ void Init()
|
|||||||
SConfig::Init();
|
SConfig::Init();
|
||||||
VideoBackend::PopulateList();
|
VideoBackend::PopulateList();
|
||||||
WiimoteReal::LoadSettings();
|
WiimoteReal::LoadSettings();
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
SI_GCAdapter::Init();
|
||||||
|
#endif
|
||||||
VideoBackend::ActivateBackend(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend);
|
VideoBackend::ActivateBackend(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend);
|
||||||
|
|
||||||
SetEnableAlert(SConfig::GetInstance().m_LocalCoreStartupParameter.bUsePanicHandlers);
|
SetEnableAlert(SConfig::GetInstance().m_LocalCoreStartupParameter.bUsePanicHandlers);
|
||||||
@ -30,6 +35,9 @@ void Init()
|
|||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
|
#if defined(__LIBUSB__) || defined (_WIN32)
|
||||||
|
SI_GCAdapter::Shutdown();
|
||||||
|
#endif
|
||||||
WiimoteReal::Shutdown();
|
WiimoteReal::Shutdown();
|
||||||
VideoBackend::ClearList();
|
VideoBackend::ClearList();
|
||||||
SConfig::Shutdown();
|
SConfig::Shutdown();
|
||||||
|
Reference in New Issue
Block a user