service: hid: Migrate hidbus to new interface

This commit is contained in:
Narr the Reg 2024-02-07 16:43:28 -06:00
parent c10e720ba9
commit b4d88a7bb4
10 changed files with 259 additions and 400 deletions

View file

@ -36,7 +36,7 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings));
server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); server_manager->RegisterNamedService("hidbus", std::make_shared<Hidbus>(system));
server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system)); server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system));
server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system)); server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system));

View file

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

View file

@ -5,8 +5,10 @@
#include <functional> #include <functional>
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
#include "hid_core/hidbus/hidbus_base.h" #include "hid_core/hidbus/hidbus_base.h"
namespace Core::Timing { namespace Core::Timing {
@ -19,10 +21,10 @@ class System;
namespace Service::HID { namespace Service::HID {
class HidBus final : public ServiceFramework<HidBus> { class Hidbus final : public ServiceFramework<Hidbus> {
public: public:
explicit HidBus(Core::System& system_); explicit Hidbus(Core::System& system_);
~HidBus() override; ~Hidbus() override;
private: private:
static const std::size_t max_number_of_handles = 0x13; static const std::size_t max_number_of_handles = 0x13;
@ -41,7 +43,7 @@ private:
}; };
// This is nn::hidbus::BusType // This is nn::hidbus::BusType
enum class BusType : u32 { enum class BusType : u64 {
LeftJoyRail, LeftJoyRail,
RightJoyRail, RightJoyRail,
InternalBus, // Lark microphone InternalBus, // Lark microphone
@ -51,11 +53,15 @@ private:
// This is nn::hidbus::BusHandle // This is nn::hidbus::BusHandle
struct BusHandle { struct BusHandle {
u32 abstracted_pad_id; union {
u8 internal_index; u64 raw{};
u8 player_number;
u8 bus_type_id; BitField<0, 32, u64> abstracted_pad_id;
bool is_valid; BitField<32, 8, u64> internal_index;
BitField<40, 8, u64> player_number;
BitField<48, 8, u64> bus_type_id;
BitField<56, 1, u64> is_valid;
};
}; };
static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size"); static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size");
@ -94,19 +100,38 @@ private:
std::unique_ptr<HidbusBase> device{nullptr}; std::unique_ptr<HidbusBase> device{nullptr};
}; };
void GetBusHandle(HLERequestContext& ctx); Result GetBusHandle(Out<bool> out_is_valid, Out<BusHandle> out_bus_handle,
void IsExternalDeviceConnected(HLERequestContext& ctx); Core::HID::NpadIdType npad_id, BusType bus_type,
void Initialize(HLERequestContext& ctx); AppletResourceUserId aruid);
void Finalize(HLERequestContext& ctx);
void EnableExternalDevice(HLERequestContext& ctx); Result IsExternalDeviceConnected(Out<bool> out_is_connected, BusHandle bus_handle);
void GetExternalDeviceId(HLERequestContext& ctx);
void SendCommandAsync(HLERequestContext& ctx); Result Initialize(BusHandle bus_handle, AppletResourceUserId aruid);
void GetSendCommandAsynceResult(HLERequestContext& ctx);
void SetEventForSendCommandAsycResult(HLERequestContext& ctx); Result Finalize(BusHandle bus_handle, AppletResourceUserId aruid);
void GetSharedMemoryHandle(HLERequestContext& ctx);
void EnableJoyPollingReceiveMode(HLERequestContext& ctx); Result EnableExternalDevice(bool is_enabled, BusHandle bus_handle, u64 inval,
void DisableJoyPollingReceiveMode(HLERequestContext& ctx); AppletResourceUserId aruid);
void SetStatusManagerType(HLERequestContext& ctx);
Result GetExternalDeviceId(Out<u32> out_device_id, BusHandle bus_handle);
Result SendCommandAsync(BusHandle bus_handle, InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
Result GetSendCommandAsynceResult(Out<u64> out_data_size, BusHandle bus_handle,
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_data);
Result SetEventForSendCommandAsycResult(OutCopyHandle<Kernel::KReadableEvent> out_event,
BusHandle bus_handle);
Result GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory);
Result EnableJoyPollingReceiveMode(u32 t_mem_size, JoyPollingMode polling_mode,
BusHandle bus_handle,
InCopyHandle<Kernel::KTransferMemory> t_mem);
Result DisableJoyPollingReceiveMode(BusHandle bus_handle);
Result SetStatusManagerType(StatusManagerType manager_type);
void UpdateHidbus(std::chrono::nanoseconds ns_late); void UpdateHidbus(std::chrono::nanoseconds ns_late);
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const; std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;

View file

@ -160,7 +160,7 @@ public:
} }
// Returns a reply from a command // Returns a reply from a command
virtual std::vector<u8> GetReply() const { virtual u64 GetReply(std::span<u8> out_data) const {
return {}; return {};
} }

View file

@ -90,32 +90,32 @@ u8 RingController::GetDeviceId() const {
return device_id; return device_id;
} }
std::vector<u8> RingController::GetReply() const { u64 RingController::GetReply(std::span<u8> out_data) const {
const RingConCommands current_command = command; const RingConCommands current_command = command;
switch (current_command) { switch (current_command) {
case RingConCommands::GetFirmwareVersion: case RingConCommands::GetFirmwareVersion:
return GetFirmwareVersionReply(); return GetFirmwareVersionReply(out_data);
case RingConCommands::ReadId: case RingConCommands::ReadId:
return GetReadIdReply(); return GetReadIdReply(out_data);
case RingConCommands::c20105: case RingConCommands::c20105:
return GetC020105Reply(); return GetC020105Reply(out_data);
case RingConCommands::ReadUnkCal: case RingConCommands::ReadUnkCal:
return GetReadUnkCalReply(); return GetReadUnkCalReply(out_data);
case RingConCommands::ReadFactoryCal: case RingConCommands::ReadFactoryCal:
return GetReadFactoryCalReply(); return GetReadFactoryCalReply(out_data);
case RingConCommands::ReadUserCal: case RingConCommands::ReadUserCal:
return GetReadUserCalReply(); return GetReadUserCalReply(out_data);
case RingConCommands::ReadRepCount: case RingConCommands::ReadRepCount:
return GetReadRepCountReply(); return GetReadRepCountReply(out_data);
case RingConCommands::ReadTotalPushCount: case RingConCommands::ReadTotalPushCount:
return GetReadTotalPushCountReply(); return GetReadTotalPushCountReply(out_data);
case RingConCommands::ResetRepCount: case RingConCommands::ResetRepCount:
return GetResetRepCountReply(); return GetResetRepCountReply(out_data);
case RingConCommands::SaveCalData: case RingConCommands::SaveCalData:
return GetSaveDataReply(); return GetSaveDataReply(out_data);
default: default:
return GetErrorReply(); return GetErrorReply(out_data);
} }
} }
@ -163,16 +163,16 @@ bool RingController::SetCommand(std::span<const u8> data) {
} }
} }
std::vector<u8> RingController::GetFirmwareVersionReply() const { u64 RingController::GetFirmwareVersionReply(std::span<u8> out_data) const {
const FirmwareVersionReply reply{ const FirmwareVersionReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.firmware = version, .firmware = version,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadIdReply() const { u64 RingController::GetReadIdReply(std::span<u8> out_data) const {
// The values are hardcoded from a real joycon // The values are hardcoded from a real joycon
const ReadIdReply reply{ const ReadIdReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
@ -184,83 +184,83 @@ std::vector<u8> RingController::GetReadIdReply() const {
.id_h_x4 = 8245, .id_h_x4 = 8245,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetC020105Reply() const { u64 RingController::GetC020105Reply(std::span<u8> out_data) const {
const Cmd020105Reply reply{ const Cmd020105Reply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = 1, .data = 1,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadUnkCalReply() const { u64 RingController::GetReadUnkCalReply(std::span<u8> out_data) const {
const ReadUnkCalReply reply{ const ReadUnkCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = 0, .data = 0,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadFactoryCalReply() const { u64 RingController::GetReadFactoryCalReply(std::span<u8> out_data) const {
const ReadFactoryCalReply reply{ const ReadFactoryCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.calibration = factory_calibration, .calibration = factory_calibration,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadUserCalReply() const { u64 RingController::GetReadUserCalReply(std::span<u8> out_data) const {
const ReadUserCalReply reply{ const ReadUserCalReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.calibration = user_calibration, .calibration = user_calibration,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadRepCountReply() const { u64 RingController::GetReadRepCountReply(std::span<u8> out_data) const {
const GetThreeByteReply reply{ const GetThreeByteReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = {total_rep_count, 0, 0}, .data = {total_rep_count, 0, 0},
.crc = GetCrcValue({total_rep_count, 0, 0, 0}), .crc = GetCrcValue({total_rep_count, 0, 0, 0}),
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetReadTotalPushCountReply() const { u64 RingController::GetReadTotalPushCountReply(std::span<u8> out_data) const {
const GetThreeByteReply reply{ const GetThreeByteReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
.data = {total_push_count, 0, 0}, .data = {total_push_count, 0, 0},
.crc = GetCrcValue({total_push_count, 0, 0, 0}), .crc = GetCrcValue({total_push_count, 0, 0, 0}),
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetResetRepCountReply() const { u64 RingController::GetResetRepCountReply(std::span<u8> out_data) const {
return GetReadRepCountReply(); return GetReadRepCountReply(out_data);
} }
std::vector<u8> RingController::GetSaveDataReply() const { u64 RingController::GetSaveDataReply(std::span<u8> out_data) const {
const StatusReply reply{ const StatusReply reply{
.status = DataValid::Valid, .status = DataValid::Valid,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
std::vector<u8> RingController::GetErrorReply() const { u64 RingController::GetErrorReply(std::span<u8> out_data) const {
const ErrorReply reply{ const ErrorReply reply{
.status = DataValid::BadCRC, .status = DataValid::BadCRC,
}; };
return GetDataVector(reply); return GetData(reply, out_data);
} }
u8 RingController::GetCrcValue(const std::vector<u8>& data) const { u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
@ -281,12 +281,11 @@ u8 RingController::GetCrcValue(const std::vector<u8>& data) const {
} }
template <typename T> template <typename T>
std::vector<u8> RingController::GetDataVector(const T& reply) const { u64 RingController::GetData(const T& reply, std::span<u8> out_data) const {
static_assert(std::is_trivially_copyable_v<T>); static_assert(std::is_trivially_copyable_v<T>);
std::vector<u8> data; const auto data_size = static_cast<u64>(std::min(sizeof(reply), out_data.size()));
data.resize(sizeof(reply)); std::memcpy(out_data.data(), &reply, data_size);
std::memcpy(data.data(), &reply, sizeof(reply)); return data_size;
return data;
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -34,7 +34,7 @@ public:
bool SetCommand(std::span<const u8> data) override; bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command // Returns a reply from a command
std::vector<u8> GetReply() const override; u64 GetReply(std::span<u8> data) const override;
private: private:
// These values are obtained from a real ring controller // These values are obtained from a real ring controller
@ -184,44 +184,44 @@ private:
RingConData GetSensorValue() const; RingConData GetSensorValue() const;
// Returns 8 byte reply with firmware version // Returns 8 byte reply with firmware version
std::vector<u8> GetFirmwareVersionReply() const; u64 GetFirmwareVersionReply(std::span<u8> out_data) const;
// Returns 16 byte reply with ID values // Returns 16 byte reply with ID values
std::vector<u8> GetReadIdReply() const; u64 GetReadIdReply(std::span<u8> out_data) const;
// (STUBBED) Returns 8 byte reply // (STUBBED) Returns 8 byte reply
std::vector<u8> GetC020105Reply() const; u64 GetC020105Reply(std::span<u8> out_data) const;
// (STUBBED) Returns 8 byte empty reply // (STUBBED) Returns 8 byte empty reply
std::vector<u8> GetReadUnkCalReply() const; u64 GetReadUnkCalReply(std::span<u8> out_data) const;
// Returns 20 byte reply with factory calibration values // Returns 20 byte reply with factory calibration values
std::vector<u8> GetReadFactoryCalReply() const; u64 GetReadFactoryCalReply(std::span<u8> out_data) const;
// Returns 20 byte reply with user calibration values // Returns 20 byte reply with user calibration values
std::vector<u8> GetReadUserCalReply() const; u64 GetReadUserCalReply(std::span<u8> out_data) const;
// Returns 8 byte reply // Returns 8 byte reply
std::vector<u8> GetReadRepCountReply() const; u64 GetReadRepCountReply(std::span<u8> out_data) const;
// Returns 8 byte reply // Returns 8 byte reply
std::vector<u8> GetReadTotalPushCountReply() const; u64 GetReadTotalPushCountReply(std::span<u8> out_data) const;
// Returns 8 byte reply // Returns 8 byte reply
std::vector<u8> GetResetRepCountReply() const; u64 GetResetRepCountReply(std::span<u8> out_data) const;
// Returns 4 byte save data reply // Returns 4 byte save data reply
std::vector<u8> GetSaveDataReply() const; u64 GetSaveDataReply(std::span<u8> out_data) const;
// Returns 8 byte error reply // Returns 8 byte error reply
std::vector<u8> GetErrorReply() const; u64 GetErrorReply(std::span<u8> out_data) const;
// Returns 8 bit redundancy check from provided data // Returns 8 bit redundancy check from provided data
u8 GetCrcValue(const std::vector<u8>& data) const; u8 GetCrcValue(const std::vector<u8>& data) const;
// Converts structs to an u8 vector equivalent // Converts structs to an u8 vector equivalent
template <typename T> template <typename T>
std::vector<u8> GetDataVector(const T& reply) const; u64 GetData(const T& reply, std::span<u8> out_data) const;
RingConCommands command{RingConCommands::Error}; RingConCommands command{RingConCommands::Error};

View file

@ -38,7 +38,7 @@ u8 Starlink::GetDeviceId() const {
return DEVICE_ID; return DEVICE_ID;
} }
std::vector<u8> Starlink::GetReply() const { u64 Starlink::GetReply(std::span<u8> out_data) const {
return {}; return {};
} }

View file

@ -31,7 +31,7 @@ public:
bool SetCommand(std::span<const u8> data) override; bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command // Returns a reply from a command
std::vector<u8> GetReply() const override; u64 GetReply(std::span<u8> out_data) const override;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -38,7 +38,7 @@ u8 HidbusStubbed::GetDeviceId() const {
return DEVICE_ID; return DEVICE_ID;
} }
std::vector<u8> HidbusStubbed::GetReply() const { u64 HidbusStubbed::GetReply(std::span<u8> out_data) const {
return {}; return {};
} }

View file

@ -31,7 +31,7 @@ public:
bool SetCommand(std::span<const u8> data) override; bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command // Returns a reply from a command
std::vector<u8> GetReply() const override; u64 GetReply(std::span<u8> out_data) const override;
}; };
} // namespace Service::HID } // namespace Service::HID