diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 123 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 10 |
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 | ||
| 1233 | void 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 | |||
| 1293 | void 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 | |||
| 1218 | void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 1335 | void 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{}; |