|
|
|
@ -9,6 +9,7 @@ |
|
|
|
#include "core/hle/kernel/k_readable_event.h"
|
|
|
|
#include "core/hle/kernel/k_shared_memory.h"
|
|
|
|
#include "core/hle/kernel/k_transfer_memory.h"
|
|
|
|
#include "core/hle/service/cmif_serialization.h"
|
|
|
|
#include "core/hle/service/hid/hidbus.h"
|
|
|
|
#include "core/hle/service/ipc_helpers.h"
|
|
|
|
#include "core/hle/service/service.h"
|
|
|
|
@ -22,25 +23,25 @@ namespace Service::HID { |
|
|
|
// (15ms, 66Hz)
|
|
|
|
constexpr auto hidbus_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; |
|
|
|
|
|
|
|
HidBus::HidBus(Core::System& system_) |
|
|
|
Hidbus::Hidbus(Core::System& system_) |
|
|
|
: ServiceFramework{system_, "hidbus"}, service_context{system_, service_name} { |
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
static const FunctionInfo functions[] = { |
|
|
|
{1, &HidBus::GetBusHandle, "GetBusHandle"}, |
|
|
|
{2, &HidBus::IsExternalDeviceConnected, "IsExternalDeviceConnected"}, |
|
|
|
{3, &HidBus::Initialize, "Initialize"}, |
|
|
|
{4, &HidBus::Finalize, "Finalize"}, |
|
|
|
{5, &HidBus::EnableExternalDevice, "EnableExternalDevice"}, |
|
|
|
{6, &HidBus::GetExternalDeviceId, "GetExternalDeviceId"}, |
|
|
|
{7, &HidBus::SendCommandAsync, "SendCommandAsync"}, |
|
|
|
{8, &HidBus::GetSendCommandAsynceResult, "GetSendCommandAsynceResult"}, |
|
|
|
{9, &HidBus::SetEventForSendCommandAsycResult, "SetEventForSendCommandAsycResult"}, |
|
|
|
{10, &HidBus::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, |
|
|
|
{11, &HidBus::EnableJoyPollingReceiveMode, "EnableJoyPollingReceiveMode"}, |
|
|
|
{12, &HidBus::DisableJoyPollingReceiveMode, "DisableJoyPollingReceiveMode"}, |
|
|
|
{1, C<&Hidbus::GetBusHandle>, "GetBusHandle"}, |
|
|
|
{2, C<&Hidbus::IsExternalDeviceConnected>, "IsExternalDeviceConnected"}, |
|
|
|
{3, C<&Hidbus::Initialize>, "Initialize"}, |
|
|
|
{4, C<&Hidbus::Finalize>, "Finalize"}, |
|
|
|
{5, C<&Hidbus::EnableExternalDevice>, "EnableExternalDevice"}, |
|
|
|
{6, C<&Hidbus::GetExternalDeviceId>, "GetExternalDeviceId"}, |
|
|
|
{7, C<&Hidbus::SendCommandAsync>, "SendCommandAsync"}, |
|
|
|
{8, C<&Hidbus::GetSendCommandAsynceResult>, "GetSendCommandAsynceResult"}, |
|
|
|
{9, C<&Hidbus::SetEventForSendCommandAsycResult>, "SetEventForSendCommandAsycResult"}, |
|
|
|
{10, C<&Hidbus::GetSharedMemoryHandle>, "GetSharedMemoryHandle"}, |
|
|
|
{11, C<&Hidbus::EnableJoyPollingReceiveMode>, "EnableJoyPollingReceiveMode"}, |
|
|
|
{12, C<&Hidbus::DisableJoyPollingReceiveMode>, "DisableJoyPollingReceiveMode"}, |
|
|
|
{13, nullptr, "GetPollingData"}, |
|
|
|
{14, &HidBus::SetStatusManagerType, "SetStatusManagerType"}, |
|
|
|
{14, C<&Hidbus::SetStatusManagerType>, "SetStatusManagerType"}, |
|
|
|
}; |
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
@ -60,11 +61,11 @@ HidBus::HidBus(Core::System& system_) |
|
|
|
hidbus_update_event); |
|
|
|
} |
|
|
|
|
|
|
|
HidBus::~HidBus() { |
|
|
|
Hidbus::~Hidbus() { |
|
|
|
system.CoreTiming().UnscheduleEvent(hidbus_update_event); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { |
|
|
|
void Hidbus::UpdateHidbus(std::chrono::nanoseconds ns_late) { |
|
|
|
if (is_hidbus_enabled) { |
|
|
|
for (std::size_t i = 0; i < devices.size(); ++i) { |
|
|
|
if (!devices[i].is_device_initialized) { |
|
|
|
@ -84,7 +85,7 @@ void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const { |
|
|
|
std::optional<std::size_t> Hidbus::GetDeviceIndexFromHandle(BusHandle handle) const { |
|
|
|
for (std::size_t i = 0; i < devices.size(); ++i) { |
|
|
|
const auto& device_handle = devices[i].handle; |
|
|
|
if (handle.abstracted_pad_id == device_handle.abstracted_pad_id && |
|
|
|
@ -98,20 +99,11 @@ std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) co |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::GetBusHandle(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
struct Parameters { |
|
|
|
Core::HID::NpadIdType npad_id; |
|
|
|
INSERT_PADDING_WORDS_NOINIT(1); |
|
|
|
BusType bus_type; |
|
|
|
u64 applet_resource_user_id; |
|
|
|
}; |
|
|
|
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); |
|
|
|
|
|
|
|
const auto parameters{rp.PopRaw<Parameters>()}; |
|
|
|
|
|
|
|
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}", |
|
|
|
parameters.npad_id, parameters.bus_type, parameters.applet_resource_user_id); |
|
|
|
Result Hidbus::GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle, |
|
|
|
Core::HID::NpadIdType npad_id, BusType bus_type, |
|
|
|
AppletResourceUserId aruid) { |
|
|
|
LOG_INFO(Service_HID, "called, npad_id={}, bus_type={}, applet_resource_user_id={}", npad_id, |
|
|
|
bus_type, aruid.pid); |
|
|
|
|
|
|
|
bool is_handle_found = 0; |
|
|
|
std::size_t handle_index = 0; |
|
|
|
@ -121,8 +113,8 @@ void HidBus::GetBusHandle(HLERequestContext& ctx) { |
|
|
|
if (!handle.is_valid) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (static_cast<Core::HID::NpadIdType>(handle.player_number) == parameters.npad_id && |
|
|
|
handle.bus_type_id == static_cast<u8>(parameters.bus_type)) { |
|
|
|
if (handle.player_number.As<Core::HID::NpadIdType>() == npad_id && |
|
|
|
handle.bus_type_id == static_cast<u8>(bus_type)) { |
|
|
|
is_handle_found = true; |
|
|
|
handle_index = i; |
|
|
|
break; |
|
|
|
@ -135,388 +127,231 @@ void HidBus::GetBusHandle(HLERequestContext& ctx) { |
|
|
|
if (devices[i].handle.is_valid) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
devices[i].handle = { |
|
|
|
.abstracted_pad_id = static_cast<u8>(i), |
|
|
|
.internal_index = static_cast<u8>(i), |
|
|
|
.player_number = static_cast<u8>(parameters.npad_id), |
|
|
|
.bus_type_id = static_cast<u8>(parameters.bus_type), |
|
|
|
.is_valid = true, |
|
|
|
}; |
|
|
|
devices[i].handle.raw = 0; |
|
|
|
devices[i].handle.abstracted_pad_id.Assign(i); |
|
|
|
devices[i].handle.internal_index.Assign(i); |
|
|
|
devices[i].handle.player_number.Assign(static_cast<u8>(npad_id)); |
|
|
|
devices[i].handle.bus_type_id.Assign(static_cast<u8>(bus_type)); |
|
|
|
devices[i].handle.is_valid.Assign(true); |
|
|
|
handle_index = i; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
struct OutData { |
|
|
|
bool is_valid; |
|
|
|
INSERT_PADDING_BYTES(7); |
|
|
|
BusHandle handle; |
|
|
|
}; |
|
|
|
static_assert(sizeof(OutData) == 0x10, "OutData has incorrect size."); |
|
|
|
|
|
|
|
const OutData out_data{ |
|
|
|
.is_valid = true, |
|
|
|
.handle = devices[handle_index].handle, |
|
|
|
}; |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 6}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.PushRaw(out_data); |
|
|
|
*out_is_valid = true; |
|
|
|
*out_bus_handle = devices[handle_index].handle; |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::IsExternalDeviceConnected(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle) { |
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"Called, abstracted_pad_id={}, bus_type={}, internal_index={}, " |
|
|
|
"player_number={}, is_valid={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto& device = devices[device_index.value()].device; |
|
|
|
const bool is_attached = device->IsDeviceActivated(); |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.Push(is_attached); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
*out_is_connected = devices[device_index.value()].device->IsDeviceActivated(); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::Initialize(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
const auto applet_resource_user_id{rp.Pop<u64>()}; |
|
|
|
|
|
|
|
Result Hidbus::Initialize(BusHandle bus_handle, AppletResourceUserId aruid) { |
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, abstracted_pad_id={} bus_type={} internal_index={} " |
|
|
|
"player_number={} is_valid={}, applet_resource_user_id={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id); |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid, aruid.pid); |
|
|
|
|
|
|
|
is_hidbus_enabled = true; |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto entry_index = devices[device_index.value()].handle.internal_index; |
|
|
|
auto& cur_entry = hidbus_status.entries[entry_index]; |
|
|
|
|
|
|
|
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { |
|
|
|
MakeDevice<RingController>(bus_handle_); |
|
|
|
devices[device_index.value()].is_device_initialized = true; |
|
|
|
devices[device_index.value()].device->ActivateDevice(); |
|
|
|
cur_entry.is_in_focus = true; |
|
|
|
cur_entry.is_connected = true; |
|
|
|
cur_entry.is_connected_result = ResultSuccess; |
|
|
|
cur_entry.is_enabled = false; |
|
|
|
cur_entry.is_polling_mode = false; |
|
|
|
} else { |
|
|
|
MakeDevice<HidbusStubbed>(bus_handle_); |
|
|
|
devices[device_index.value()].is_device_initialized = true; |
|
|
|
cur_entry.is_in_focus = true; |
|
|
|
cur_entry.is_connected = false; |
|
|
|
cur_entry.is_connected_result = ResultSuccess; |
|
|
|
cur_entry.is_enabled = false; |
|
|
|
cur_entry.is_polling_mode = false; |
|
|
|
} |
|
|
|
|
|
|
|
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status, |
|
|
|
sizeof(hidbus_status)); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
} |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
void HidBus::Finalize(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
const auto applet_resource_user_id{rp.Pop<u64>()}; |
|
|
|
|
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, " |
|
|
|
"player_number={}, is_valid={}, applet_resource_user_id={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto entry_index = devices[device_index.value()].handle.internal_index; |
|
|
|
auto& cur_entry = hidbus_status.entries[entry_index]; |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
devices[device_index.value()].is_device_initialized = false; |
|
|
|
device->DeactivateDevice(); |
|
|
|
const auto entry_index = devices[device_index.value()].handle.internal_index; |
|
|
|
auto& cur_entry = hidbus_status.entries[entry_index]; |
|
|
|
|
|
|
|
if (bus_handle.internal_index == 0 && Settings::values.enable_ring_controller) { |
|
|
|
MakeDevice<RingController>(bus_handle); |
|
|
|
devices[device_index.value()].is_device_initialized = true; |
|
|
|
devices[device_index.value()].device->ActivateDevice(); |
|
|
|
cur_entry.is_in_focus = true; |
|
|
|
cur_entry.is_connected = true; |
|
|
|
cur_entry.is_connected_result = ResultSuccess; |
|
|
|
cur_entry.is_enabled = false; |
|
|
|
cur_entry.is_polling_mode = false; |
|
|
|
} else { |
|
|
|
MakeDevice<HidbusStubbed>(bus_handle); |
|
|
|
devices[device_index.value()].is_device_initialized = true; |
|
|
|
cur_entry.is_in_focus = true; |
|
|
|
cur_entry.is_connected = false; |
|
|
|
cur_entry.is_connected_result = ResultSuccess; |
|
|
|
cur_entry.is_enabled = false; |
|
|
|
cur_entry.is_polling_mode = false; |
|
|
|
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status, |
|
|
|
sizeof(hidbus_status)); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status, |
|
|
|
sizeof(hidbus_status)); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::EnableExternalDevice(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
struct Parameters { |
|
|
|
bool enable; |
|
|
|
INSERT_PADDING_BYTES_NOINIT(7); |
|
|
|
BusHandle bus_handle; |
|
|
|
u64 inval; |
|
|
|
u64 applet_resource_user_id; |
|
|
|
}; |
|
|
|
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); |
|
|
|
|
|
|
|
const auto parameters{rp.PopRaw<Parameters>()}; |
|
|
|
Result Hidbus::Finalize(BusHandle bus_handle, AppletResourceUserId aruid) { |
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, " |
|
|
|
"player_number={}, is_valid={}, applet_resource_user_id={}", |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid, aruid.pid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
const auto entry_index = devices[device_index.value()].handle.internal_index; |
|
|
|
auto& cur_entry = hidbus_status.entries[entry_index]; |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
devices[device_index.value()].is_device_initialized = false; |
|
|
|
device->DeactivateDevice(); |
|
|
|
|
|
|
|
cur_entry.is_in_focus = true; |
|
|
|
cur_entry.is_connected = false; |
|
|
|
cur_entry.is_connected_result = ResultSuccess; |
|
|
|
cur_entry.is_enabled = false; |
|
|
|
cur_entry.is_polling_mode = false; |
|
|
|
std::memcpy(system.Kernel().GetHidBusSharedMem().GetPointer(), &hidbus_status, |
|
|
|
sizeof(hidbus_status)); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
Result Hidbus::EnableExternalDevice(bool is_enabled, BusHandle bus_handle, u64 inval, |
|
|
|
AppletResourceUserId aruid) { |
|
|
|
LOG_DEBUG(Service_HID, |
|
|
|
"called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " |
|
|
|
"player_number={}, is_valid={}, inval={}, applet_resource_user_id{}", |
|
|
|
parameters.enable, parameters.bus_handle.abstracted_pad_id, |
|
|
|
parameters.bus_handle.bus_type_id, parameters.bus_handle.internal_index, |
|
|
|
parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval, |
|
|
|
parameters.applet_resource_user_id); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->Enable(parameters.enable); |
|
|
|
is_enabled, bus_handle.abstracted_pad_id, bus_handle.bus_type_id, |
|
|
|
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid, inval, |
|
|
|
aruid.pid); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
devices[device_index.value()].device->Enable(is_enabled); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::GetExternalDeviceId(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::GetExternalDeviceId(Out<u32> out_device_id, BusHandle bus_handle) { |
|
|
|
LOG_DEBUG(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " |
|
|
|
"is_valid={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto& device = devices[device_index.value()].device; |
|
|
|
u32 device_id = device->GetDeviceId(); |
|
|
|
IPC::ResponseBuilder rb{ctx, 3}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.Push<u32>(device_id); |
|
|
|
return; |
|
|
|
} |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
} |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
void HidBus::SendCommandAsync(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto data = ctx.ReadBuffer(); |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
*out_device_id = devices[device_index.value()].device->GetDeviceId(); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
Result Hidbus::SendCommandAsync(BusHandle bus_handle, |
|
|
|
InBuffer<BufferAttr_HipcAutoSelect> buffer_data) { |
|
|
|
LOG_DEBUG(Service_HID, |
|
|
|
"called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, " |
|
|
|
"player_number={}, is_valid={}", |
|
|
|
data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, |
|
|
|
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
buffer_data.size(), bus_handle.abstracted_pad_id, bus_handle.bus_type_id, |
|
|
|
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->SetCommand(data); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
devices[device_index.value()].device->SetCommand(buffer_data); |
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
|
|
|
|
void HidBus::GetSendCommandAsynceResult(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::GetSendCommandAsynceResult(Out<u64> out_data_size, BusHandle bus_handle, |
|
|
|
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_data) { |
|
|
|
LOG_DEBUG(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " |
|
|
|
"is_valid={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto& device = devices[device_index.value()].device; |
|
|
|
const std::vector<u8> data = device->GetReply(); |
|
|
|
const u64 data_size = ctx.WriteBuffer(data); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 4}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.Push<u64>(data_size); |
|
|
|
return; |
|
|
|
} |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
*out_data_size = devices[device_index.value()].device->GetReply(out_buffer_data); |
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
|
|
|
|
void HidBus::SetEventForSendCommandAsycResult(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::SetEventForSendCommandAsycResult(OutCopyHandle<Kernel::KReadableEvent> out_event, |
|
|
|
BusHandle bus_handle) { |
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " |
|
|
|
"is_valid={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
const auto& device = devices[device_index.value()].device; |
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.PushCopyObjects(device->GetSendCommandAsycEvent()); |
|
|
|
return; |
|
|
|
} |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
*out_event = &devices[device_index.value()].device->GetSendCommandAsycEvent(); |
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
|
|
|
|
void HidBus::GetSharedMemoryHandle(HLERequestContext& ctx) { |
|
|
|
Result Hidbus::GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) { |
|
|
|
LOG_DEBUG(Service_HID, "called"); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
rb.PushCopyObjects(&system.Kernel().GetHidBusSharedMem()); |
|
|
|
*out_shared_memory = &system.Kernel().GetHidBusSharedMem(); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto t_mem_size{rp.Pop<u32>()}; |
|
|
|
const auto t_mem_handle{ctx.GetCopyHandle(0)}; |
|
|
|
const auto polling_mode_{rp.PopEnum<JoyPollingMode>()}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode polling_mode, |
|
|
|
BusHandle bus_handle, |
|
|
|
InCopyHandle<Kernel::KTransferMemory> t_mem) { |
|
|
|
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); |
|
|
|
|
|
|
|
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); |
|
|
|
|
|
|
|
if (t_mem.IsNull()) { |
|
|
|
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
ASSERT_MSG(t_mem->GetSize() == 0x1000, "t_mem has incorrect size"); |
|
|
|
ASSERT_MSG(t_mem->GetSize() == t_mem_size, "t_mem has incorrect size"); |
|
|
|
|
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, t_mem_handle=0x{:08X}, polling_mode={}, abstracted_pad_id={}, bus_type={}, " |
|
|
|
"called, polling_mode={}, abstracted_pad_id={}, bus_type={}, " |
|
|
|
"internal_index={}, player_number={}, is_valid={}", |
|
|
|
t_mem_handle, polling_mode_, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, |
|
|
|
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
polling_mode, bus_handle.abstracted_pad_id, bus_handle.bus_type_id, |
|
|
|
bus_handle.internal_index, bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->SetPollingMode(polling_mode_); |
|
|
|
device->SetTransferMemoryAddress(t_mem->GetSourceAddress()); |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->SetPollingMode(polling_mode); |
|
|
|
device->SetTransferMemoryAddress(t_mem->GetSourceAddress()); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::DisableJoyPollingReceiveMode(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto bus_handle_{rp.PopRaw<BusHandle>()}; |
|
|
|
|
|
|
|
Result Hidbus::DisableJoyPollingReceiveMode(BusHandle bus_handle) { |
|
|
|
LOG_INFO(Service_HID, |
|
|
|
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, " |
|
|
|
"is_valid={}", |
|
|
|
bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index, |
|
|
|
bus_handle_.player_number, bus_handle_.is_valid); |
|
|
|
bus_handle.abstracted_pad_id, bus_handle.bus_type_id, bus_handle.internal_index, |
|
|
|
bus_handle.player_number, bus_handle.is_valid); |
|
|
|
|
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle_); |
|
|
|
const auto device_index = GetDeviceIndexFromHandle(bus_handle); |
|
|
|
|
|
|
|
if (device_index) { |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->DisablePollingMode(); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
return; |
|
|
|
} |
|
|
|
R_UNLESS(device_index.has_value(), ResultUnknown); |
|
|
|
|
|
|
|
LOG_ERROR(Service_HID, "Invalid handle"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultUnknown); |
|
|
|
return; |
|
|
|
auto& device = devices[device_index.value()].device; |
|
|
|
device->DisablePollingMode(); |
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
|
|
|
|
void HidBus::SetStatusManagerType(HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto manager_type{rp.PopEnum<StatusManagerType>()}; |
|
|
|
|
|
|
|
Result Hidbus::SetStatusManagerType(StatusManagerType manager_type) { |
|
|
|
LOG_WARNING(Service_HID, "(STUBBED) called, manager_type={}", manager_type); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ResultSuccess); |
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace Service::HID
|