mc.mitm: add support for dualshock3 controller

This commit is contained in:
ndeadly 2023-04-11 15:56:48 +02:00
parent 07b6334094
commit e22959174e
18 changed files with 579 additions and 16 deletions

View file

@ -31,6 +31,7 @@ Use controllers from other consoles natively on your Nintendo Switch via Bluetoo
* __Nintendo Wii Remote + extensions (Nunchuck, Classic Controller, Classic Controller Pro, SNES Mini, TaTaCon (Taiko drum), MotionPlus)__
* __Nintendo Wii Balance Board (experimental)__
* __Nintendo WiiU Pro Controller__
* __Sony Dualshock3 (Playstation 3) Controller__
* __Sony DualShock4 (Playstation 4) Controller__
* __Sony Dualsense (Playstation 5) Controller__
* __Sony Dualsense Edge Controller__
@ -101,6 +102,11 @@ Press the red sync button on the back of the controller. The controller LEDs wil
It is recommended that you perform an analog stick calibration for these controller types where applicable, as every controller has different analog stick range and center position but unlike Switch controllers, there is no stored factory calibration.
***Sony Dualshock3 Controller***
To pair this controller, you will need to connect it to the console via USB cable. Once the controller LEDs start flashing, disconnect the USB cable and hit the `PS` button.
*Note: to avoid unwanted behaviour if using the controller in USB wired mode, this only works from the usual `Controllers->Change Grip/Order` screen.*
***Sony Dualshock4/Dualsense Controllers***
Press and hold the `PS` + `share` buttons simultaneously until the lightbar starts blinking. When done correctly the blink pattern will resemble a heartbeat, otherwise it will blink on and off at a constant rate.
@ -132,6 +138,7 @@ These settings can be used to spoof your switch bluetooth to appear as another d
- `[misc]`
These are miscellaneous controller-specific settings etc.
- `dualshock3_led_mode` Set Dualshock 3 player LED behaviour. Valid modes [0-1] where 0=Switch pattern, 1=PS3 pattern
- `dualshock4_polling_rate` Set polling rate for Sony Dualshock 4 controllers. Valid range [0-16] where 0=max, 16=min. Refer [here](https://github.com/ndeadly/MissionControl/blob/4a0326308d1ff39353b045f5efb1a99c4a504c28/mc_mitm/source/controllers/dualshock4_controller.hpp#L21) for corresponding frequency values.
- `dualshock4_lightbar_brightness` Set LED lightbar brightness for Sony Dualshock 4 controllers. Valid range [0-9] where 0=off, 1=min, 2-9=12.5-100% in 12.5% increments.
- `dualsense_lightbar_brightness` Set LED lightbar brightness for Sony Dualsense controllers. Valid range [0-9] where 0=off, 1=min, 2-9=12.5-100% in 12.5% increments.
@ -236,9 +243,6 @@ For more details on the various controller revisions (with images), see [here](h
***My Xbox One/Elite V2 controller used to connect and now it doesn't, what gives?***
As of late 2021, Microsoft introduced a new controller firmware that aims to bring Xbox One/Elite 2 controllers in line with the newer Series X|S controllers. Updating to this firmware switches the controller over to using Bluetooth Low Energy (LE), a newer bluetooth standard focused on low power consumption, which is not currently supported by Mission Control. If your controller firmware is version 5.xx.xxxx.x or above, you have the new LE firmware and will need to downgrade to the legacy one (see https://support.xbox.com/en-US/help/hardware-network/accessories/controller-firmware-reversion)
***Can you add support for PS3 (Dualshock3) controllers?***
~~It's on my list of things to look into. The pairing process is non-standard and may require modifications to the Bluetooth driver. If it can be done non-destructively I will add support eventually.~~ Having looked into this a bit, it appears it's going to be a lot of work given the constraints of HOS (if it can even be done without breaking support for other Bluetooth controllers). I won't rule out a solution in the future, but this is not high priority for me right now. Sorry DS3 owners.
***Can you add support for Xbox 360 controllers?***
No, not currently. These don't use Bluetooth. Try sys-con with a wireless USB adapter.

@ -1 +1 @@
Subproject commit af0d008900128d8679b80569f69fe562ed7d6681
Subproject commit b1607dc8a3d85bc8c859c60d70ebb4a3dcbb85b8

@ -1 +1 @@
Subproject commit 03007f7b9b1e16d9bc5fb239be1980e077288749
Subproject commit db592d8aebd047cabf8925b25fbf20d08d1c0495

View file

@ -11,6 +11,8 @@
;host_address=04:20:69:04:20:69
[misc]
; Set Dualshock 3 player LED behaviour. Valid modes [0-1] where 0=Switch pattern, 1=PS3 pattern [default 0]
;dualshock3_led_mode=0
; Set polling rate for Sony Dualshock 4 controllers. Valid range [0-16] where 0=max, 16=min [default 8 (125Hz)]
; Refer to https://github.com/ndeadly/MissionControl/blob/4a0326308d1ff39353b045f5efb1a99c4a504c28/mc_mitm/source/controllers/dualshock4_controller.hpp#L21
;dualshock4_polling_rate=8

View file

@ -54,6 +54,12 @@ namespace ams::controller {
}
}
for (auto hwId : Dualshock3Controller::hardware_ids) {
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
return ControllerType_Dualshock3;
}
}
for (auto hwId : Dualshock4Controller::hardware_ids) {
if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) {
return ControllerType_Dualshock4;
@ -206,6 +212,9 @@ namespace ams::controller {
case ControllerType_Wii:
controller = std::make_shared<WiiController>(address, id);
break;
case ControllerType_Dualshock3:
controller = std::make_shared<Dualshock3Controller>(address, id);
break;
case ControllerType_Dualshock4:
controller = std::make_shared<Dualshock4Controller>(address, id);
break;

View file

@ -19,6 +19,7 @@
#include "switch_controller.hpp"
#include "wii_controller.hpp"
#include "dualshock3_controller.hpp"
#include "dualshock4_controller.hpp"
#include "dualsense_controller.hpp"
#include "xbox_one_controller.hpp"
@ -48,6 +49,7 @@ namespace ams::controller {
enum ControllerType {
ControllerType_Switch,
ControllerType_Wii,
ControllerType_Dualshock3,
ControllerType_Dualshock4,
ControllerType_Dualsense,
ControllerType_XboxOne,

View file

@ -254,7 +254,7 @@ namespace ams::controller {
Result DualsenseController::GetVersionInfo(DualsenseVersionInfo *version_info) {
bluetooth::HidReport output;
R_TRY(this->GetFeatureReport(0x20, &output));
R_TRY(this->GetReport(0x20, BtdrvBluetoothHhReportType_Feature, &output));
auto response = reinterpret_cast<DualsenseReportData *>(&output.data);
std::memcpy(version_info, &response->feature0x20.version_info, sizeof(DualsenseVersionInfo));
@ -264,7 +264,7 @@ namespace ams::controller {
Result DualsenseController::GetCalibrationData(DualsenseImuCalibrationData *calibration) {
bluetooth::HidReport output;
R_TRY(this->GetFeatureReport(0x05, &output));
R_TRY(this->GetReport(0x05, BtdrvBluetoothHhReportType_Feature, &output));
auto response = reinterpret_cast<DualsenseReportData *>(&output.data);
std::memcpy(calibration, &response->feature0x05.calibration, sizeof(DualsenseImuCalibrationData));

View file

@ -0,0 +1,292 @@
/*
* Copyright (C) 2020-2023 ndeadly
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dualshock3_controller.hpp"
#include "../bluetooth_mitm/bluetooth/bluetooth_core.hpp"
#include "../mcmitm_config.hpp"
#include <stratosphere.hpp>
#include <cstdlib>
namespace ams::controller {
namespace {
const char *ds3_device_name = "PLAYSTATION(R)3 Controller";
constexpr u16 ds3_vendor_id = 0x054c;
constexpr u16 ds3_product_id = 0x0268;
enum Dualshock3LedMode {
Dualshock3LedMode_Switch,
Dualshock3LedMode_Ps3
};
const u8 enable_payload[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
const u8 led_config[] = { 0xff, 0x27, 0x10, 0x00, 0x32 };
const u8 player_led_patterns[] = { 0b1000, 0b1100, 0b1110, 0b1111, 0b1001, 0b0101, 0b1101, 0b0110 };
constexpr float stick_scale_factor = float(UINT12_MAX) / UINT8_MAX;
alignas(os::MemoryPageSize) constinit u8 g_usb_buffer[0x1000];
Result SetMasterAddress(UsbHsClientIfSession *if_session, const BtdrvAddress *address) {
const struct {
u8 unk1;
u8 unk2;
BtdrvAddress address;
} data = {0x01, 0x00, *address};
std::memcpy(&g_usb_buffer, &data, sizeof(data));
u32 rx_size = 0;
Result rc = usbHsIfCtrlXfer(if_session,
USB_ENDPOINT_OUT | (0x01 << 5) | 0x01,
USB_REQUEST_SET_CONFIGURATION,
0x3f5,
0,
sizeof(data),
&g_usb_buffer,
&rx_size
);
R_RETURN(rc);
}
Result GetSlaveAddress(UsbHsClientIfSession *if_session, BtdrvAddress *address) {
u32 tx_size = 0;
Result rc = usbHsIfCtrlXfer(if_session,
USB_ENDPOINT_IN | (0x01 << 5) | 0x01,
USB_REQUEST_CLEAR_FEATURE,
0x3f2,
0,
18,
&g_usb_buffer,
&tx_size
);
if (R_SUCCEEDED(rc))
*address = *reinterpret_cast<BtdrvAddress *>(&g_usb_buffer[4]);
R_RETURN(rc);
}
Result TrustDevice(const BtdrvAddress *address) {
SetSysBluetoothDevicesSettings device = {};
device.addr = *address;
device.class_of_device = {0x00, 0x05, 0x08};
device.link_key_present = false;
device.trusted_services = 0x100000;
device.vid = ds3_vendor_id;
device.pid = ds3_product_id;
device.sub_class = 0x08;
device.attribute_mask = 0xff;
if (hos::GetVersion() < hos::Version_13_0_0) {
std::strncpy(device.name.name, ds3_device_name, sizeof(device.name));
}
else {
std::strncpy(device.name2, ds3_device_name, sizeof(device.name2));
}
R_RETURN(btdrvAddPairedDeviceInfo(&device));
}
void SignalBondComplete(const BtdrvAddress *address) {
if (hos::GetVersion() < hos::Version_9_0_0) {
const struct {
BtdrvAddress addr;
u8 pad[2];
u32 status;
u32 type;
} bond_event = { *address, {0}, 0, BtdrvConnectionEventType_Suspended };
bluetooth::core::SignalFakeEvent(BtdrvEventTypeOld_Connection, &bond_event, sizeof(bond_event));
} else if (hos::GetVersion() < hos::Version_12_0_0) {
const struct {
u32 status;
BtdrvAddress addr;
u8 pad[2];
u32 type;
} bond_event = { 0, *address, {0}, BtdrvConnectionEventType_Suspended };
bluetooth::core::SignalFakeEvent(BtdrvEventTypeOld_Connection, &bond_event, sizeof(bond_event));
} else {
const struct {
u32 type;
BtdrvAddress addr;
u8 reserved[0xfe];
} bond_event = { BtdrvConnectionEventType_Suspended, *address, {0} };
bluetooth::core::SignalFakeEvent(BtdrvEventType_Connection, &bond_event, sizeof(bond_event));
}
}
}
bool Dualshock3Controller::UsbIdentify(UsbHsInterface *iface) {
return (iface->device_desc.idVendor == ds3_vendor_id) && (iface->device_desc.idProduct == ds3_product_id);
}
Result Dualshock3Controller::UsbPair(UsbHsInterface *iface) {
// Acquire usb:hs client interface session
UsbHsClientIfSession if_session;
R_TRY(usbHsAcquireUsbIf(&if_session, iface));
// Close session on function exit
ON_SCOPE_EXIT {
if (usbHsIfIsActive(&if_session)) {
usbHsIfClose(&if_session);
}
};
// Fetch the console bluetooth address
BtdrvAdapterProperty property;
R_TRY(btdrvGetAdapterProperty(BtdrvAdapterPropertyType_Address, &property));
// Set the console address as the master on the DS3
BtdrvAddress master_address = *reinterpret_cast<BtdrvAddress *>(property.data);
R_TRY(SetMasterAddress(&if_session, &master_address));
// Get the address of the DS3
BtdrvAddress slave_address;
R_TRY(GetSlaveAddress(&if_session, &slave_address));
// Add DS3 to list of trusted devices
R_TRY(TrustDevice(&slave_address));
// Signal fake bonding success event for btm
SignalBondComplete(&slave_address);
R_SUCCEED();
}
Result Dualshock3Controller::Initialize() {
R_TRY(EmulatedSwitchController::Initialize());
R_TRY(this->SendEnablePayload());
R_SUCCEED();
}
Result Dualshock3Controller::SetVibration(const SwitchRumbleData *rumble_data) {
m_rumble_state.amp_motor_left = static_cast<u8>(255 * std::max(rumble_data[0].low_band_amp, rumble_data[1].low_band_amp));
m_rumble_state.amp_motor_right = static_cast<u8>(255 * std::max(rumble_data[0].high_band_amp, rumble_data[1].high_band_amp));
R_RETURN(this->PushRumbleLedState());
}
Result Dualshock3Controller::CancelVibration() {
m_rumble_state.amp_motor_left = 0;
m_rumble_state.amp_motor_right = 0;
R_RETURN(this->PushRumbleLedState());
}
Result Dualshock3Controller::SetPlayerLed(u8 led_mask) {
u8 player_index;
R_TRY(LedsMaskToPlayerNumber(led_mask, &player_index));
auto config = mitm::GetGlobalConfig();
if (config->misc.dualshock3_led_mode == Dualshock3LedMode_Ps3) {
if (player_index < 4) {
m_led_mask = 1 << player_index;
} else {
m_led_mask = ~(1 << player_index) & 0x0f;
}
} else {
m_led_mask = player_led_patterns[player_index];
}
R_RETURN(this->PushRumbleLedState());
}
void Dualshock3Controller::ProcessInputData(const bluetooth::HidReport *report) {
auto ds3_report = reinterpret_cast<const Dualshock3ReportData *>(&report->data);
switch(ds3_report->id) {
case 0x01:
this->MapInputReport0x01(ds3_report); break;
default:
break;
}
}
void Dualshock3Controller::MapInputReport0x01(const Dualshock3ReportData *src) {
m_left_stick.SetData(
static_cast<u16>(stick_scale_factor * src->input0x01.left_stick.x) & UINT12_MAX,
static_cast<u16>(stick_scale_factor * (UINT8_MAX - src->input0x01.left_stick.y)) & UINT12_MAX
);
m_right_stick.SetData(
static_cast<u16>(stick_scale_factor * src->input0x01.right_stick.x) & UINT12_MAX,
static_cast<u16>(stick_scale_factor * (UINT8_MAX - src->input0x01.right_stick.y)) & UINT12_MAX
);
m_buttons.dpad_down = src->input0x01.buttons.dpad_down;
m_buttons.dpad_up = src->input0x01.buttons.dpad_up;
m_buttons.dpad_right = src->input0x01.buttons.dpad_right;
m_buttons.dpad_left = src->input0x01.buttons.dpad_left;
m_buttons.A = src->input0x01.buttons.circle;
m_buttons.B = src->input0x01.buttons.cross;
m_buttons.X = src->input0x01.buttons.triangle;
m_buttons.Y = src->input0x01.buttons.square;
m_buttons.R = src->input0x01.buttons.R1;
m_buttons.ZR = src->input0x01.buttons.R2;
m_buttons.L = src->input0x01.buttons.L1;
m_buttons.ZL = src->input0x01.buttons.L2;
m_buttons.minus = src->input0x01.buttons.select;
m_buttons.plus = src->input0x01.buttons.start;
m_buttons.lstick_press = src->input0x01.buttons.L3;
m_buttons.rstick_press = src->input0x01.buttons.R3;
m_buttons.home = src->input0x01.buttons.ps;
m_charging = src->input0x01.charge == 0x02;
m_battery = std::clamp<u8>(src->input0x01.battery, 0, 4) * 2;
// Workaround for controller reporting battery empty and being disconnected under certain conditions
if (m_battery == 0) {
m_battery = 1;
}
}
Result Dualshock3Controller::SendEnablePayload() {
m_output_report.size = sizeof(enable_payload);
std::memcpy(m_output_report.data, enable_payload, m_output_report.size);
R_RETURN(this->SetReport(BtdrvBluetoothHhReportType_Feature, &m_output_report));
}
Result Dualshock3Controller::PushRumbleLedState() {
std::scoped_lock lk(m_output_mutex);
Dualshock3ReportData report = {};
report.id = 0x01;
report.output0x01.data[1] = 10;
report.output0x01.data[2] = m_rumble_state.amp_motor_right ? 1 : 0;
report.output0x01.data[3] = 10;
report.output0x01.data[4] = m_rumble_state.amp_motor_left;
report.output0x01.data[9] = m_led_mask << 1;
std::memcpy(&report.output0x01.data[10], led_config, sizeof(led_config));
std::memcpy(&report.output0x01.data[15], led_config, sizeof(led_config));
std::memcpy(&report.output0x01.data[20], led_config, sizeof(led_config));
std::memcpy(&report.output0x01.data[25], led_config, sizeof(led_config));
m_output_report.size = sizeof(report.output0x01) + sizeof(report.id);
std::memcpy(m_output_report.data, &report, m_output_report.size);
R_RETURN(this->SetReport(BtdrvBluetoothHhReportType_Output, &m_output_report));
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (C) 2020-2023 ndeadly
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "emulated_switch_controller.hpp"
namespace ams::controller {
struct Dualshock3StickData {
u8 x;
u8 y;
} PACKED;
struct Dualshock3ButtonData {
u8 select : 1;
u8 L3 : 1;
u8 R3 : 1;
u8 start : 1;
u8 dpad_up : 1;
u8 dpad_right : 1;
u8 dpad_down : 1;
u8 dpad_left : 1;
u8 L2 : 1;
u8 R2 : 1;
u8 L1 : 1;
u8 R1 : 1;
u8 triangle : 1;
u8 circle : 1;
u8 cross : 1;
u8 square : 1;
u8 ps : 1;
u8 : 0;
} PACKED;
struct Dualshock3RumbleData {
u8 amp_motor_left;
u8 amp_motor_right;
} PACKED;
struct Dualshock3InputReport0x01 {
u8 unk0;
Dualshock3ButtonData buttons;
u8 unk1;
Dualshock3StickData left_stick;
Dualshock3StickData right_stick;
u8 unk2[4];
u8 pressure_dpad_up;
u8 pressure_dpad_right;
u8 pressure_dpad_down;
u8 pressure_dpad_left;
u8 left_trigger;
u8 right_trigger;
u8 unk3[2];
u8 pressure_triangle;
u8 pressure_circle;
u8 pressure_cross;
u8 pressure_square;
u8 unk4[3];
u8 charge;
u8 battery;
u8 connection;
u8 unk5[9];
u16 accel_x;
u16 accel_y;
u16 accel_z;
u16 gyro_x;
} PACKED;
struct Dualshock3OutputReport0x01 {
struct {
u8 data[35];
};
} PACKED;
struct Dualshock3ReportData {
u8 id;
union {
Dualshock3InputReport0x01 input0x01;
Dualshock3OutputReport0x01 output0x01;
};
} PACKED;
class Dualshock3Controller final : public EmulatedSwitchController {
public:
static constexpr const HardwareID hardware_ids[] = {
{0x054c, 0x0268}, // Official Dualshock3
};
static bool UsbIdentify(UsbHsInterface *iface);
static Result UsbPair(UsbHsInterface *iface);
public:
Dualshock3Controller(const bluetooth::Address *address, HardwareID id)
: EmulatedSwitchController(address, id) { }
Result Initialize(void);
Result SetVibration(const SwitchRumbleData *rumble_data);
Result CancelVibration();
Result SetPlayerLed(u8 led_mask);
void ProcessInputData(const bluetooth::HidReport *report) override;
private:
void MapInputReport0x01(const Dualshock3ReportData *src);
Result SendEnablePayload(void);
Result PushRumbleLedState();
u8 m_led_mask;
Dualshock3RumbleData m_rumble_state;
};
}

View file

@ -217,7 +217,7 @@ namespace ams::controller {
Result Dualshock4Controller::GetVersionInfo(Dualshock4VersionInfo *version_info) {
bluetooth::HidReport output;
R_TRY(this->GetFeatureReport(0x06, &output));
R_TRY(this->GetReport(0x06, BtdrvBluetoothHhReportType_Feature, &output));
auto response = reinterpret_cast<Dualshock4ReportData *>(&output.data);
std::memcpy(version_info, &response->feature0x06.version_info, sizeof(Dualshock4VersionInfo));
@ -227,7 +227,7 @@ namespace ams::controller {
Result Dualshock4Controller::GetCalibrationData(Dualshock4ImuCalibrationData *calibration) {
bluetooth::HidReport output;
R_TRY(this->GetFeatureReport(0x05, &output));
R_TRY(this->GetReport(0x05, BtdrvBluetoothHhReportType_Feature, &output));
auto response = reinterpret_cast<Dualshock4ReportData *>(&output.data);
std::memcpy(calibration, &response->feature0x05.calibration, sizeof(Dualshock4ImuCalibrationData));

View file

@ -167,12 +167,12 @@ namespace ams::controller {
R_SUCCEED();
}
Result SwitchController::SetFeatureReport(const bluetooth::HidReport *report) {
Result SwitchController::SetReport(BtdrvBluetoothHhReportType type, const bluetooth::HidReport *report) {
auto response = std::make_shared<HidResponse>(BtdrvHidEventType_SetReport);
m_future_responses.push(response);
ON_SCOPE_EXIT { m_future_responses.pop(); };
R_TRY(btdrvSetHidReport(m_address, BtdrvBluetoothHhReportType_Feature, report));
R_TRY(btdrvSetHidReport(m_address, type, report));
if (!response->TimedWait(ams::TimeSpan::FromMilliSeconds(500))) {
return -1; // This should return a proper failure code
@ -183,12 +183,12 @@ namespace ams::controller {
return response_data.set_report.res;
}
Result SwitchController::GetFeatureReport(u8 id, bluetooth::HidReport *out_report) {
Result SwitchController::GetReport(u8 id, BtdrvBluetoothHhReportType type, bluetooth::HidReport *out_report) {
auto response = std::make_shared<HidResponse>(BtdrvHidEventType_GetReport);
m_future_responses.push(response);
ON_SCOPE_EXIT { m_future_responses.pop(); };
R_TRY(btdrvGetHidReport(m_address, id, BtdrvBluetoothHhReportType_Feature));
R_TRY(btdrvGetHidReport(m_address, id, type));
if (!response->TimedWait(ams::TimeSpan::FromMilliSeconds(500))) {
return -1; // This should return a proper failure code

View file

@ -358,8 +358,8 @@ namespace ams::controller {
protected:
Result WriteDataReport(const bluetooth::HidReport *report);
Result WriteDataReport(const bluetooth::HidReport *report, u8 response_id, bluetooth::HidReport *out_report);
Result SetFeatureReport(const bluetooth::HidReport *report);
Result GetFeatureReport(u8 id, bluetooth::HidReport *out_report);
Result SetReport(BtdrvBluetoothHhReportType type, const bluetooth::HidReport *report);
Result GetReport(u8 id, BtdrvBluetoothHhReportType type, bluetooth::HidReport *out_report);
virtual void UpdateControllerState(const bluetooth::HidReport *report);
virtual void ApplyButtonCombos(SwitchButtonData *buttons);

View file

@ -30,6 +30,7 @@ namespace ams::mitm {
.enable_motion = true
},
.misc = {
.dualshock3_led_mode = 0,
.dualshock4_polling_rate = 8,
.dualshock4_lightbar_brightness = 5,
.dualsense_lightbar_brightness = 5,
@ -91,7 +92,9 @@ namespace ams::mitm {
ParseBluetoothAddress(value, &config->bluetooth.host_address);
}
} else if (strcasecmp(section, "misc") == 0) {
if (strcasecmp(name, "dualshock4_polling_rate") == 0) {
if (strcasecmp(name, "dualshock3_led_mode") == 0) {
ParseInt(value, &config->misc.dualshock3_led_mode, 0, 1);
} else if (strcasecmp(name, "dualshock4_polling_rate") == 0) {
ParseInt(value, &config->misc.dualshock4_polling_rate, 0, 16);
} else if (strcasecmp(name, "dualshock4_lightbar_brightness") == 0) {
ParseInt(value, &config->misc.dualshock4_lightbar_brightness, 0, 9);

View file

@ -29,6 +29,7 @@ namespace ams::mitm {
} bluetooth;
struct {
int dualshock3_led_mode;
int dualshock4_polling_rate;
int dualshock4_lightbar_brightness;
int dualsense_lightbar_brightness;

View file

@ -27,6 +27,7 @@
#include "bluetooth_mitm/bluetooth/bluetooth_hid.hpp"
#include "bluetooth_mitm/bluetooth/bluetooth_hid_report.hpp"
#include "bluetooth_mitm/bluetooth/bluetooth_ble.hpp"
#include "usb/mc_usb_handler.hpp"
namespace ams::mitm {
@ -88,6 +89,12 @@ namespace ams::mitm {
}
g_init_event.Signal();
// Loop until we can initialise btm:sys
while (R_FAILED(btmsysInitialize())) {
os::SleepThread(ams::TimeSpan::FromMilliSeconds(200));
}
}
}
@ -113,9 +120,11 @@ namespace ams::mitm {
R_ABORT_UNLESS(ams::mitm::bluetooth::Launch());
R_ABORT_UNLESS(ams::mitm::btm::Launch());
R_ABORT_UNLESS(ams::mitm::mc::Launch());
R_ABORT_UNLESS(ams::usb::Launch());
}
void WaitModules() {
ams::usb::WaitFinished();
ams::mitm::mc::WaitFinished();
ams::mitm::btm::WaitFinished();
ams::mitm::bluetooth::WaitFinished();

View file

@ -66,6 +66,7 @@ namespace ams {
R_ABORT_UNLESS(pmdmntInitialize());
R_ABORT_UNLESS(pminfoInitialize());
R_ABORT_UNLESS(usbHsInitialize());
R_ABORT_UNLESS(fs::MountSdCard("sdmc"));
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2020-2023 ndeadly
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mc_usb_handler.hpp"
#include "../controllers/dualshock3_controller.hpp"
namespace ams::usb {
namespace {
const UsbHsInterfaceFilter g_if_filter = {
.Flags = UsbHsInterfaceFilterFlags_bcdDevice_Min | UsbHsInterfaceFilterFlags_bInterfaceClass,
.bcdDevice_Min = 0,
.bInterfaceClass = USB_CLASS_HID,
};
Result HandleUsbHsInterfaceAvailableEvent() {
s32 total_entries = 0;
UsbHsInterface interfaces[8] = {};
R_TRY(usbHsQueryAvailableInterfaces(&g_if_filter, interfaces, sizeof(interfaces), &total_entries));
for(int i = 0; i < total_entries; ++i) {
if (controller::Dualshock3Controller::UsbIdentify(&interfaces[i])) {
bool pairing_started = false;
R_TRY(btmsysIsGamepadPairingStarted(&pairing_started));
if (pairing_started) {
R_TRY(controller::Dualshock3Controller::UsbPair(&interfaces[i]));
}
}
}
R_SUCCEED();
}
const s32 ThreadPriority = 9;
const size_t ThreadStackSize = 0x2000;
alignas(os::ThreadStackAlignment) u8 g_thread_stack[ThreadStackSize];
os::ThreadType g_thread;
void UsbThreadFunction(void *) {
Event if_event;
R_ABORT_UNLESS(usbHsCreateInterfaceAvailableEvent(&if_event, true, 0, &g_if_filter));
os::SystemEvent interface_available_event;
interface_available_event.AttachReadableHandle(if_event.revent, false, os::EventClearMode_AutoClear);
for (;;) {
interface_available_event.Wait();
R_ABORT_UNLESS(HandleUsbHsInterfaceAvailableEvent());
}
usbHsDestroyInterfaceAvailableEvent(&if_event, 0);
}
}
Result Launch() {
R_TRY(os::CreateThread(&g_thread,
UsbThreadFunction,
nullptr,
g_thread_stack,
ThreadStackSize,
ThreadPriority
));
os::SetThreadNamePointer(&g_thread, "mc::UsbThread");
os::StartThread(&g_thread);
return ams::ResultSuccess();
}
void WaitFinished() {
os::WaitThread(&g_thread);
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020-2023 ndeadly
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::usb {
Result Launch();
void WaitFinished();
}