summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/hid/hid.cpp123
-rw-r--r--src/core/hle/service/hid/hid.h10
2 files changed, 130 insertions, 3 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1e2677320..3d0fe42f6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -273,8 +273,8 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
273 {204, &Hid::PermitVibration, "PermitVibration"}, 273 {204, &Hid::PermitVibration, "PermitVibration"},
274 {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"}, 274 {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"},
275 {206, &Hid::SendVibrationValues, "SendVibrationValues"}, 275 {206, &Hid::SendVibrationValues, "SendVibrationValues"},
276 {207, nullptr, "SendVibrationGcErmCommand"}, 276 {207, &Hid::SendVibrationGcErmCommand, "SendVibrationGcErmCommand"},
277 {208, nullptr, "GetActualVibrationGcErmCommand"}, 277 {208, &Hid::GetActualVibrationGcErmCommand, "GetActualVibrationGcErmCommand"},
278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 278 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, 279 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, 280 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
@@ -1093,7 +1093,22 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
1093 1093
1094 VibrationDeviceInfo vibration_device_info; 1094 VibrationDeviceInfo vibration_device_info;
1095 1095
1096 vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; 1096 switch (vibration_device_handle.npad_type) {
1097 case Controller_NPad::NpadType::ProController:
1098 case Controller_NPad::NpadType::Handheld:
1099 case Controller_NPad::NpadType::JoyconDual:
1100 case Controller_NPad::NpadType::JoyconLeft:
1101 case Controller_NPad::NpadType::JoyconRight:
1102 default:
1103 vibration_device_info.type = VibrationDeviceType::LinearResonantActuator;
1104 break;
1105 case Controller_NPad::NpadType::GameCube:
1106 vibration_device_info.type = VibrationDeviceType::GcErm;
1107 break;
1108 case Controller_NPad::NpadType::Pokeball:
1109 vibration_device_info.type = VibrationDeviceType::Unknown;
1110 break;
1111 }
1097 1112
1098 switch (vibration_device_handle.device_index) { 1113 switch (vibration_device_handle.device_index) {
1099 case Controller_NPad::DeviceIndex::Left: 1114 case Controller_NPad::DeviceIndex::Left:
@@ -1215,6 +1230,108 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
1215 rb.Push(RESULT_SUCCESS); 1230 rb.Push(RESULT_SUCCESS);
1216} 1231}
1217 1232
1233void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
1234 IPC::RequestParser rp{ctx};
1235 struct Parameters {
1236 Controller_NPad::DeviceHandle vibration_device_handle;
1237 u64 applet_resource_user_id;
1238 VibrationGcErmCommand gc_erm_command;
1239 };
1240 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1241
1242 const auto parameters{rp.PopRaw<Parameters>()};
1243
1244 /**
1245 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1246 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
1247 * in order to differentiate between Stop and StopHard commands.
1248 * This is done to reuse the controller vibration functions made for regular controllers.
1249 */
1250 const auto vibration_value = [parameters] {
1251 switch (parameters.gc_erm_command) {
1252 case VibrationGcErmCommand::Stop:
1253 return Controller_NPad::VibrationValue{
1254 .amp_low = 0.0f,
1255 .freq_low = 160.0f,
1256 .amp_high = 0.0f,
1257 .freq_high = 320.0f,
1258 };
1259 case VibrationGcErmCommand::Start:
1260 return Controller_NPad::VibrationValue{
1261 .amp_low = 1.0f,
1262 .freq_low = 160.0f,
1263 .amp_high = 1.0f,
1264 .freq_high = 320.0f,
1265 };
1266 case VibrationGcErmCommand::StopHard:
1267 return Controller_NPad::VibrationValue{
1268 .amp_low = 0.0f,
1269 .freq_low = 0.0f,
1270 .amp_high = 0.0f,
1271 .freq_high = 0.0f,
1272 };
1273 default:
1274 return Controller_NPad::DEFAULT_VIBRATION_VALUE;
1275 }
1276 }();
1277
1278 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1279 .VibrateController(parameters.vibration_device_handle, vibration_value);
1280
1281 LOG_DEBUG(Service_HID,
1282 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
1283 "gc_erm_command={}",
1284 parameters.vibration_device_handle.npad_type,
1285 parameters.vibration_device_handle.npad_id,
1286 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
1287 parameters.gc_erm_command);
1288
1289 IPC::ResponseBuilder rb{ctx, 2};
1290 rb.Push(RESULT_SUCCESS);
1291}
1292
1293void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
1294 IPC::RequestParser rp{ctx};
1295 struct Parameters {
1296 Controller_NPad::DeviceHandle vibration_device_handle;
1297 INSERT_PADDING_WORDS_NOINIT(1);
1298 u64 applet_resource_user_id;
1299 };
1300
1301 const auto parameters{rp.PopRaw<Parameters>()};
1302
1303 const auto last_vibration = applet_resource->GetController<Controller_NPad>(HidController::NPad)
1304 .GetLastVibration(parameters.vibration_device_handle);
1305
1306 const auto gc_erm_command = [last_vibration] {
1307 if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) {
1308 return VibrationGcErmCommand::Start;
1309 }
1310
1311 /**
1312 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1313 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
1314 * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
1315 * This is done to reuse the controller vibration functions made for regular controllers.
1316 */
1317 if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) {
1318 return VibrationGcErmCommand::StopHard;
1319 }
1320
1321 return VibrationGcErmCommand::Stop;
1322 }();
1323
1324 LOG_DEBUG(Service_HID,
1325 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1326 parameters.vibration_device_handle.npad_type,
1327 parameters.vibration_device_handle.npad_id,
1328 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1329
1330 IPC::ResponseBuilder rb{ctx, 4};
1331 rb.Push(RESULT_SUCCESS);
1332 rb.PushEnum(gc_erm_command);
1333}
1334
1218void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 1335void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
1219 IPC::RequestParser rp{ctx}; 1336 IPC::RequestParser rp{ctx};
1220 const auto applet_resource_user_id{rp.Pop<u64>()}; 1337 const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 7cc0433e2..99d155586 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -136,6 +136,8 @@ private:
136 void PermitVibration(Kernel::HLERequestContext& ctx); 136 void PermitVibration(Kernel::HLERequestContext& ctx);
137 void IsVibrationPermitted(Kernel::HLERequestContext& ctx); 137 void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
138 void SendVibrationValues(Kernel::HLERequestContext& ctx); 138 void SendVibrationValues(Kernel::HLERequestContext& ctx);
139 void SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx);
140 void GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx);
139 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); 141 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
140 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); 142 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
141 void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx); 143 void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);
@@ -154,7 +156,9 @@ private:
154 void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); 156 void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
155 157
156 enum class VibrationDeviceType : u32 { 158 enum class VibrationDeviceType : u32 {
159 Unknown = 0,
157 LinearResonantActuator = 1, 160 LinearResonantActuator = 1,
161 GcErm = 2,
158 }; 162 };
159 163
160 enum class VibrationDevicePosition : u32 { 164 enum class VibrationDevicePosition : u32 {
@@ -163,6 +167,12 @@ private:
163 Right = 2, 167 Right = 2,
164 }; 168 };
165 169
170 enum class VibrationGcErmCommand : u64 {
171 Stop = 0,
172 Start = 1,
173 StopHard = 2,
174 };
175
166 struct VibrationDeviceInfo { 176 struct VibrationDeviceInfo {
167 VibrationDeviceType type{}; 177 VibrationDeviceType type{};
168 VibrationDevicePosition position{}; 178 VibrationDevicePosition position{};