diff options
Diffstat (limited to 'src')
96 files changed, 3636 insertions, 259 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 85354f43e..a88551fbc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ include_directories(.) add_subdirectory(common) add_subdirectory(core) +add_subdirectory(audio_core) add_subdirectory(video_core) add_subdirectory(input_common) add_subdirectory(tests) diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt new file mode 100644 index 000000000..81121167d --- /dev/null +++ b/src/audio_core/CMakeLists.txt @@ -0,0 +1,23 @@ +add_library(audio_core STATIC + audio_out.cpp + audio_out.h + buffer.h + cubeb_sink.cpp + cubeb_sink.h + null_sink.h + stream.cpp + stream.h + sink.h + sink_details.cpp + sink_details.h + sink_stream.h +) + +create_target_directory_groups(audio_core) + +target_link_libraries(audio_core PUBLIC common core) + +if(ENABLE_CUBEB) + target_link_libraries(audio_core PRIVATE cubeb) + target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) +endif() diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp new file mode 100644 index 000000000..77cedb6ba --- /dev/null +++ b/src/audio_core/audio_out.cpp @@ -0,0 +1,57 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "audio_core/audio_out.h" +#include "audio_core/sink.h" +#include "audio_core/sink_details.h" +#include "common/assert.h" +#include "common/logging/log.h" + +namespace AudioCore { + +/// Returns the stream format from the specified number of channels +static Stream::Format ChannelsToStreamFormat(u32 num_channels) { + switch (num_channels) { + case 1: + return Stream::Format::Mono16; + case 2: + return Stream::Format::Stereo16; + case 6: + return Stream::Format::Multi51Channel16; + } + + LOG_CRITICAL(Audio, "Unimplemented num_channels={}", num_channels); + UNREACHABLE(); + return {}; +} + +StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, + Stream::ReleaseCallback&& release_callback) { + if (!sink) { + const SinkDetails& sink_details = GetSinkDetails("auto"); + sink = sink_details.factory(""); + } + + return std::make_shared<Stream>(sample_rate, ChannelsToStreamFormat(num_channels), + std::move(release_callback), + sink->AcquireSinkStream(sample_rate, num_channels)); +} + +std::vector<u64> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count) { + return stream->GetTagsAndReleaseBuffers(max_count); +} + +void AudioOut::StartStream(StreamPtr stream) { + stream->Play(); +} + +void AudioOut::StopStream(StreamPtr stream) { + stream->Stop(); +} + +bool AudioOut::QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<u8>&& data) { + return stream->QueueBuffer(std::make_shared<Buffer>(tag, std::move(data))); +} + +} // namespace AudioCore diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h new file mode 100644 index 000000000..8d9b695d4 --- /dev/null +++ b/src/audio_core/audio_out.h @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <vector> + +#include "audio_core/buffer.h" +#include "audio_core/sink.h" +#include "audio_core/stream.h" +#include "common/common_types.h" + +namespace AudioCore { + +/** + * Represents an audio playback interface, used to open and play audio streams + */ +class AudioOut { +public: + /// Opens a new audio stream + StreamPtr OpenStream(u32 sample_rate, u32 num_channels, + Stream::ReleaseCallback&& release_callback); + + /// Returns a vector of recently released buffers specified by tag for the specified stream + std::vector<u64> GetTagsAndReleaseBuffers(StreamPtr stream, size_t max_count); + + /// Starts an audio stream for playback + void StartStream(StreamPtr stream); + + /// Stops an audio stream that is currently playing + void StopStream(StreamPtr stream); + + /// Queues a buffer into the specified audio stream, returns true on success + bool QueueBuffer(StreamPtr stream, Buffer::Tag tag, std::vector<u8>&& data); + +private: + SinkPtr sink; +}; + +} // namespace AudioCore diff --git a/src/audio_core/buffer.h b/src/audio_core/buffer.h new file mode 100644 index 000000000..4bf5fd58a --- /dev/null +++ b/src/audio_core/buffer.h @@ -0,0 +1,40 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <vector> + +#include "common/common_types.h" + +namespace AudioCore { + +/** + * Represents a buffer of audio samples to be played in an audio stream + */ +class Buffer { +public: + using Tag = u64; + + Buffer(Tag tag, std::vector<u8>&& data) : tag{tag}, data{std::move(data)} {} + + /// Returns the raw audio data for the buffer + const std::vector<u8>& GetData() const { + return data; + } + + /// Returns the buffer tag, this is provided by the game to the audout service + Tag GetTag() const { + return tag; + } + +private: + Tag tag; + std::vector<u8> data; +}; + +using BufferPtr = std::shared_ptr<Buffer>; + +} // namespace AudioCore diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp new file mode 100644 index 000000000..34ae5b062 --- /dev/null +++ b/src/audio_core/cubeb_sink.cpp @@ -0,0 +1,190 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> + +#include "audio_core/cubeb_sink.h" +#include "audio_core/stream.h" +#include "common/logging/log.h" + +namespace AudioCore { + +class SinkStreamImpl final : public SinkStream { +public: + SinkStreamImpl(cubeb* ctx, cubeb_devid output_device) : ctx{ctx} { + cubeb_stream_params params; + params.rate = 48000; + params.channels = GetNumChannels(); + params.format = CUBEB_SAMPLE_S16NE; + params.layout = CUBEB_LAYOUT_STEREO; + + u32 minimum_latency = 0; + if (cubeb_get_min_latency(ctx, ¶ms, &minimum_latency) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error getting minimum latency"); + } + + if (cubeb_stream_init(ctx, &stream_backend, "yuzu Audio Output", nullptr, nullptr, + output_device, ¶ms, std::max(512u, minimum_latency), + &SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback, + this) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream"); + return; + } + + if (cubeb_stream_start(stream_backend) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream"); + return; + } + } + + ~SinkStreamImpl() { + if (!ctx) { + return; + } + + if (cubeb_stream_stop(stream_backend) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream"); + } + + cubeb_stream_destroy(stream_backend); + } + + void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) override { + if (!ctx) { + return; + } + + queue.reserve(queue.size() + sample_count * GetNumChannels()); + + if (num_channels == 2) { + // Copy as-is + std::copy(samples, samples + sample_count * GetNumChannels(), + std::back_inserter(queue)); + } else if (num_channels == 6) { + // Downsample 6 channels to 2 + const size_t sample_count_copy_size = sample_count * num_channels * 2; + queue.reserve(sample_count_copy_size); + for (size_t i = 0; i < sample_count * num_channels; i += num_channels) { + queue.push_back(samples[i]); + queue.push_back(samples[i + 1]); + } + } else { + ASSERT_MSG(false, "Unimplemented"); + } + } + + u32 GetNumChannels() const { + // Only support 2-channel stereo output for now + return 2; + } + +private: + std::vector<std::string> device_list; + + cubeb* ctx{}; + cubeb_stream* stream_backend{}; + + std::vector<s16> queue; + + static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* output_buffer, long num_frames); + static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); +}; + +CubebSink::CubebSink(std::string target_device_name) { + if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); + return; + } + + if (target_device_name != auto_device_name && !target_device_name.empty()) { + cubeb_device_collection collection; + if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { + LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); + } else { + const auto collection_end{collection.device + collection.count}; + const auto device{std::find_if(collection.device, collection_end, + [&](const cubeb_device_info& device) { + return target_device_name == device.friendly_name; + })}; + if (device != collection_end) { + output_device = device->devid; + } + cubeb_device_collection_destroy(ctx, &collection); + } + } +} + +CubebSink::~CubebSink() { + if (!ctx) { + return; + } + + for (auto& sink_stream : sink_streams) { + sink_stream.reset(); + } + + cubeb_destroy(ctx); +} + +SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels) { + sink_streams.push_back(std::make_unique<SinkStreamImpl>(ctx, output_device)); + return *sink_streams.back(); +} + +long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* output_buffer, long num_frames) { + SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data); + u8* buffer = reinterpret_cast<u8*>(output_buffer); + + if (!impl) { + return {}; + } + + const size_t frames_to_write{ + std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))}; + + memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels()); + impl->queue.erase(impl->queue.begin(), + impl->queue.begin() + frames_to_write * impl->GetNumChannels()); + + if (frames_to_write < num_frames) { + // Fill the rest of the frames with silence + memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0, + (num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels()); + } + + return num_frames; +} + +void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} + +std::vector<std::string> ListCubebSinkDevices() { + std::vector<std::string> device_list; + cubeb* ctx; + + if (cubeb_init(&ctx, "Citra Device Enumerator", nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); + return {}; + } + + cubeb_device_collection collection; + if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) { + LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported"); + } else { + for (size_t i = 0; i < collection.count; i++) { + const cubeb_device_info& device = collection.device[i]; + if (device.friendly_name) { + device_list.emplace_back(device.friendly_name); + } + } + cubeb_device_collection_destroy(ctx, &collection); + } + + cubeb_destroy(ctx); + return device_list; +} + +} // namespace AudioCore diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h new file mode 100644 index 000000000..d07113f1f --- /dev/null +++ b/src/audio_core/cubeb_sink.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <vector> + +#include <cubeb/cubeb.h> + +#include "audio_core/sink.h" + +namespace AudioCore { + +class CubebSink final : public Sink { +public: + explicit CubebSink(std::string device_id); + ~CubebSink() override; + + SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels) override; + +private: + cubeb* ctx{}; + cubeb_devid output_device{}; + std::vector<SinkStreamPtr> sink_streams; +}; + +std::vector<std::string> ListCubebSinkDevices(); + +} // namespace AudioCore diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h new file mode 100644 index 000000000..2e04438f7 --- /dev/null +++ b/src/audio_core/null_sink.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "audio_core/sink.h" + +namespace AudioCore { + +class NullSink final : public Sink { +public: + explicit NullSink(std::string){}; + ~NullSink() override = default; + + SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/) override { + return null_sink_stream; + } + +private: + struct NullSinkStreamImpl final : SinkStream { + void EnqueueSamples(u32 /*num_channels*/, const s16* /*samples*/, + size_t /*sample_count*/) override {} + } null_sink_stream; +}; + +} // namespace AudioCore diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h new file mode 100644 index 000000000..d1bb98c3d --- /dev/null +++ b/src/audio_core/sink.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "audio_core/sink_stream.h" +#include "common/common_types.h" + +namespace AudioCore { + +constexpr char auto_device_name[] = "auto"; + +/** + * This class is an interface for an audio sink. An audio sink accepts samples in stereo signed + * PCM16 format to be output. Sinks *do not* handle resampling and expect the correct sample rate. + * They are dumb outputs. + */ +class Sink { +public: + virtual ~Sink() = default; + virtual SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels) = 0; +}; + +using SinkPtr = std::unique_ptr<Sink>; + +} // namespace AudioCore diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp new file mode 100644 index 000000000..955ba20fb --- /dev/null +++ b/src/audio_core/sink_details.cpp @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <memory> +#include <string> +#include <vector> +#include "audio_core/null_sink.h" +#include "audio_core/sink_details.h" +#ifdef HAVE_CUBEB +#include "audio_core/cubeb_sink.h" +#endif +#include "common/logging/log.h" + +namespace AudioCore { + +// g_sink_details is ordered in terms of desirability, with the best choice at the top. +const std::vector<SinkDetails> g_sink_details = { +#ifdef HAVE_CUBEB + SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices}, +#endif + SinkDetails{"null", &std::make_unique<NullSink, std::string>, + [] { return std::vector<std::string>{"null"}; }}, +}; + +const SinkDetails& GetSinkDetails(std::string sink_id) { + auto iter = + std::find_if(g_sink_details.begin(), g_sink_details.end(), + [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; }); + + if (sink_id == "auto" || iter == g_sink_details.end()) { + if (sink_id != "auto") { + LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id); + } + // Auto-select. + // g_sink_details is ordered in terms of desirability, with the best choice at the front. + iter = g_sink_details.begin(); + } + + return *iter; +} + +} // namespace AudioCore diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h new file mode 100644 index 000000000..aa8aae1a9 --- /dev/null +++ b/src/audio_core/sink_details.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <memory> +#include <vector> + +namespace AudioCore { + +class Sink; + +struct SinkDetails { + SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>(std::string)> factory_, + std::function<std::vector<std::string>()> list_devices_) + : id(id_), factory(factory_), list_devices(list_devices_) {} + + /// Name for this sink. + const char* id; + /// A method to call to construct an instance of this type of sink. + std::function<std::unique_ptr<Sink>(std::string device_id)> factory; + /// A method to call to list available devices. + std::function<std::vector<std::string>()> list_devices; +}; + +extern const std::vector<SinkDetails> g_sink_details; + +const SinkDetails& GetSinkDetails(std::string sink_id); + +} // namespace AudioCore diff --git a/src/audio_core/sink_stream.h b/src/audio_core/sink_stream.h new file mode 100644 index 000000000..e7a3f01b0 --- /dev/null +++ b/src/audio_core/sink_stream.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "common/common_types.h" + +namespace AudioCore { + +/** + * Accepts samples in stereo signed PCM16 format to be output. Sinks *do not* handle resampling and + * expect the correct sample rate. They are dumb outputs. + */ +class SinkStream { +public: + virtual ~SinkStream() = default; + + /** + * Feed stereo samples to sink. + * @param num_channels Number of channels used. + * @param samples Samples in interleaved stereo PCM16 format. + * @param sample_count Number of samples. + */ + virtual void EnqueueSamples(u32 num_channels, const s16* samples, size_t sample_count) = 0; +}; + +using SinkStreamPtr = std::unique_ptr<SinkStream>; + +} // namespace AudioCore diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp new file mode 100644 index 000000000..689f51a1d --- /dev/null +++ b/src/audio_core/stream.cpp @@ -0,0 +1,114 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" + +#include "audio_core/sink.h" +#include "audio_core/sink_details.h" +#include "audio_core/stream.h" + +namespace AudioCore { + +constexpr size_t MaxAudioBufferCount{32}; + +u32 Stream::GetNumChannels() const { + switch (format) { + case Format::Mono16: + return 1; + case Format::Stereo16: + return 2; + case Format::Multi51Channel16: + return 6; + } + LOG_CRITICAL(Audio, "Unimplemented format={}", static_cast<u32>(format)); + UNREACHABLE(); + return {}; +} + +u32 Stream::GetSampleSize() const { + return GetNumChannels() * 2; +} + +Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, + SinkStream& sink_stream) + : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, + sink_stream{sink_stream} { + + release_event = CoreTiming::RegisterEvent( + "Stream::Release", [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); }); +} + +void Stream::Play() { + state = State::Playing; + PlayNextBuffer(); +} + +void Stream::Stop() { + ASSERT_MSG(false, "Unimplemented"); +} + +s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { + const size_t num_samples{buffer.GetData().size() / GetSampleSize()}; + return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); +} + +void Stream::PlayNextBuffer() { + if (!IsPlaying()) { + // Ensure we are in playing state before playing the next buffer + return; + } + + if (active_buffer) { + // Do not queue a new buffer if we are already playing a buffer + return; + } + + if (queued_buffers.empty()) { + // No queued buffers - we are effectively paused + return; + } + + active_buffer = queued_buffers.front(); + queued_buffers.pop(); + + sink_stream.EnqueueSamples(GetNumChannels(), + reinterpret_cast<const s16*>(active_buffer->GetData().data()), + active_buffer->GetData().size() / GetSampleSize()); + + CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); +} + +void Stream::ReleaseActiveBuffer() { + released_buffers.push(std::move(active_buffer)); + release_callback(); + PlayNextBuffer(); +} + +bool Stream::QueueBuffer(BufferPtr&& buffer) { + if (queued_buffers.size() < MaxAudioBufferCount) { + queued_buffers.push(std::move(buffer)); + PlayNextBuffer(); + return true; + } + return false; +} + +bool Stream::ContainsBuffer(Buffer::Tag tag) const { + ASSERT_MSG(false, "Unimplemented"); + return {}; +} + +std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(size_t max_count) { + std::vector<Buffer::Tag> tags; + for (size_t count = 0; count < max_count && !released_buffers.empty(); ++count) { + tags.push_back(released_buffers.front()->GetTag()); + released_buffers.pop(); + } + return tags; +} + +} // namespace AudioCore diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h new file mode 100644 index 000000000..35253920e --- /dev/null +++ b/src/audio_core/stream.h @@ -0,0 +1,103 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <memory> +#include <vector> +#include <queue> + +#include "audio_core/buffer.h" +#include "audio_core/sink_stream.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "core/core_timing.h" + +namespace AudioCore { + +/** + * Represents an audio stream, which is a sequence of queued buffers, to be outputed by AudioOut + */ +class Stream { +public: + /// Audio format of the stream + enum class Format { + Mono16, + Stereo16, + Multi51Channel16, + }; + + /// Callback function type, used to change guest state on a buffer being released + using ReleaseCallback = std::function<void()>; + + Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callback, + SinkStream& sink_stream); + + /// Plays the audio stream + void Play(); + + /// Stops the audio stream + void Stop(); + + /// Queues a buffer into the audio stream, returns true on success + bool QueueBuffer(BufferPtr&& buffer); + + /// Returns true if the audio stream contains a buffer with the specified tag + bool ContainsBuffer(Buffer::Tag tag) const; + + /// Returns a vector of recently released buffers specified by tag + std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(size_t max_count); + + /// Returns true if the stream is currently playing + bool IsPlaying() const { + return state == State::Playing; + } + + /// Returns the number of queued buffers + size_t GetQueueSize() const { + return queued_buffers.size(); + } + + /// Gets the sample rate + u32 GetSampleRate() const { + return sample_rate; + } + + /// Gets the number of channels + u32 GetNumChannels() const; + + /// Gets the sample size in bytes + u32 GetSampleSize() const; + +private: + /// Current state of the stream + enum class State { + Stopped, + Playing, + }; + + /// Plays the next queued buffer in the audio stream, starting playback if necessary + void PlayNextBuffer(); + + /// Releases the actively playing buffer, signalling that it has been completed + void ReleaseActiveBuffer(); + + /// Gets the number of core cycles when the specified buffer will be released + s64 GetBufferReleaseCycles(const Buffer& buffer) const; + + u32 sample_rate; ///< Sample rate of the stream + Format format; ///< Format of the stream + ReleaseCallback release_callback; ///< Buffer release callback for the stream + State state{State::Stopped}; ///< Playback state of the stream + CoreTiming::EventType* release_event{}; ///< Core timing release event for the stream + BufferPtr active_buffer; ///< Actively playing buffer in the stream + std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream + std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream + SinkStream& sink_stream; ///< Output sink for the stream +}; + +using StreamPtr = std::shared_ptr<Stream>; + +} // namespace AudioCore diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 93f1c0044..8b0d34da6 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -6,7 +6,7 @@ #include <string> -#if !defined(ARCHITECTURE_x86_64) && !defined(ARCHITECTURE_ARM) +#if !defined(ARCHITECTURE_x86_64) #include <cstdlib> // for exit #endif #include "common/common_types.h" @@ -32,8 +32,6 @@ #ifdef ARCHITECTURE_x86_64 #define Crash() __asm__ __volatile__("int $3") -#elif defined(ARCHITECTURE_ARM) -#define Crash() __asm__ __volatile__("trap") #else #define Crash() exit(1) #endif diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 59b999935..d86c40d26 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -169,16 +169,24 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, AOC) \ SUB(Service, APM) \ SUB(Service, BCAT) \ + SUB(Service, BTM) \ SUB(Service, Fatal) \ + SUB(Service, FGM) \ SUB(Service, Friend) \ SUB(Service, FS) \ SUB(Service, HID) \ + SUB(Service, LBL) \ + SUB(Service, LDN) \ SUB(Service, LM) \ + SUB(Service, Mii) \ SUB(Service, MM) \ + SUB(Service, NCM) \ + SUB(Service, NFC) \ SUB(Service, NFP) \ SUB(Service, NIFM) \ SUB(Service, NS) \ SUB(Service, NVDRV) \ + SUB(Service, PCIE) \ SUB(Service, PCTL) \ SUB(Service, PREPO) \ SUB(Service, SET) \ @@ -187,6 +195,7 @@ void FileBackend::Write(const Entry& entry) { SUB(Service, SSL) \ SUB(Service, Time) \ SUB(Service, VI) \ + SUB(Service, WLAN) \ CLS(HW) \ SUB(HW, Memory) \ SUB(HW, LCD) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index e7115933f..140cd8e47 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -56,16 +56,24 @@ enum class Class : ClassType { Service_APM, ///< The APM (Performance) service Service_Audio, ///< The Audio (Audio control) service Service_BCAT, ///< The BCAT service + Service_BTM, ///< The BTM service Service_Fatal, ///< The Fatal service + Service_FGM, ///< The FGM service Service_Friend, ///< The friend service Service_FS, ///< The FS (Filesystem) service Service_HID, ///< The HID (Human interface device) service + Service_LBL, ///< The LBL (LCD backlight) service + Service_LDN, ///< The LDN (Local domain network) service Service_LM, ///< The LM (Logger) service + Service_Mii, ///< The Mii service Service_MM, ///< The MM (Multimedia) service + Service_NCM, ///< The NCM service + Service_NFC, ///< The NFC (Near-field communication) service Service_NFP, ///< The NFP service Service_NIFM, ///< The NIFM (Network interface) service Service_NS, ///< The NS services Service_NVDRV, ///< The NVDRV (Nvidia driver) service + Service_PCIE, ///< The PCIe service Service_PCTL, ///< The PCTL (Parental control) service Service_PREPO, ///< The PREPO (Play report) service Service_SET, ///< The SET (Settings) service @@ -74,6 +82,7 @@ enum class Class : ClassType { Service_SSL, ///< The SSL service Service_Time, ///< The time service Service_VI, ///< The VI (Video interface) service + Service_WLAN, ///< The WLAN (Wireless local area network) service HW, ///< Low-level hardware emulation HW_Memory, ///< Memory-map and address translation HW_LCD, ///< LCD register emulation diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h index c587faefb..9609cec7c 100644 --- a/src/common/logging/text_formatter.h +++ b/src/common/logging/text_formatter.h @@ -5,6 +5,7 @@ #pragma once #include <cstddef> +#include <string> namespace Log { diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 1f0456aee..0ca663032 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <cctype> #include <cerrno> #include <cstdio> #include <cstdlib> #include <cstring> -#include <boost/range/algorithm/transform.hpp> #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -24,13 +24,15 @@ namespace Common { /// Make a string lowercase std::string ToLower(std::string str) { - boost::transform(str, str.begin(), ::tolower); + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); }); return str; } /// Make a string uppercase std::string ToUpper(std::string str) { - boost::transform(str, str.begin(), ::toupper); + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::toupper(c); }); return str; } diff --git a/src/common/swap.h b/src/common/swap.h index fc7af4280..32af0b6ac 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -69,7 +69,7 @@ inline u32 swap32(u32 _data) { inline u64 swap64(u64 _data) { return _byteswap_uint64(_data); } -#elif ARCHITECTURE_ARM +#elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6) inline u16 swap16(u16 _data) { u32 data = _data; __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); diff --git a/src/common/timer.cpp b/src/common/timer.cpp index f0c5b1a43..2dc15e434 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -3,31 +3,16 @@ // Refer to the license.txt file included. #include <ctime> - #include <fmt/format.h> - -#ifdef _WIN32 -#include <windows.h> -// windows.h needs to be included before other windows headers -#include <mmsystem.h> -#include <sys/timeb.h> -#else -#include <sys/time.h> -#endif #include "common/common_types.h" #include "common/string_util.h" #include "common/timer.h" namespace Common { -u32 Timer::GetTimeMs() { -#ifdef _WIN32 - return timeGetTime(); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); -#endif +std::chrono::milliseconds Timer::GetTimeMs() { + return std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::system_clock::now().time_since_epoch()); } // -------------------------------------------- @@ -63,7 +48,7 @@ void Timer::Update() { // ------------------------------------- // Get the number of milliseconds since the last Update() -u64 Timer::GetTimeDifference() { +std::chrono::milliseconds Timer::GetTimeDifference() { return GetTimeMs() - m_LastTime; } @@ -74,11 +59,11 @@ void Timer::AddTimeDifference() { } // Get the time elapsed since the Start() -u64 Timer::GetTimeElapsed() { +std::chrono::milliseconds Timer::GetTimeElapsed() { // If we have not started yet, return 1 (because then I don't // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) - return 1; + if (m_StartTime.count() == 0) + return std::chrono::milliseconds(1); // Return the final timer time if the timer is stopped if (!m_Running) @@ -90,49 +75,34 @@ u64 Timer::GetTimeElapsed() { // Get the formatted time elapsed since the Start() std::string Timer::GetTimeElapsedFormatted() const { // If we have not started yet, return zero - if (m_StartTime == 0) + if (m_StartTime.count() == 0) return "00:00:00:000"; // The number of milliseconds since the start. // Use a different value if the timer is stopped. - u64 Milliseconds; + std::chrono::milliseconds Milliseconds; if (m_Running) Milliseconds = GetTimeMs() - m_StartTime; else Milliseconds = m_LastTime - m_StartTime; // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); + std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds); // Minutes - u32 Minutes = Seconds / 60; + std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds); // Hours - u32 Hours = Minutes / 60; + std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds); - std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours, Minutes % 60, Seconds % 60, - Milliseconds % 1000); + std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60, + Seconds.count() % 60, Milliseconds.count() % 1000); return TmpStr; } -// Get current time -void Timer::IncreaseResolution() { -#ifdef _WIN32 - timeBeginPeriod(1); -#endif -} - -void Timer::RestoreResolution() { -#ifdef _WIN32 - timeEndPeriod(1); -#endif -} - // Get the number of seconds since January 1 1970 -u64 Timer::GetTimeSinceJan1970() { - time_t ltime; - time(<ime); - return ((u64)ltime); +std::chrono::seconds Timer::GetTimeSinceJan1970() { + return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs()); } -u64 Timer::GetLocalTimeSinceJan1970() { +std::chrono::seconds Timer::GetLocalTimeSinceJan1970() { time_t sysTime, tzDiff, tzDST; struct tm* gmTime; @@ -149,7 +119,7 @@ u64 Timer::GetLocalTimeSinceJan1970() { gmTime = gmtime(&sysTime); tzDiff = sysTime - mktime(gmTime); - return (u64)(sysTime + tzDiff + tzDST); + return std::chrono::seconds(sysTime + tzDiff + tzDST); } // Return the current time formatted as Minutes:Seconds:Milliseconds @@ -164,30 +134,16 @@ std::string Timer::GetTimeFormatted() { strftime(tmp, 6, "%M:%S", gmTime); -// Now tack on the milliseconds -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - return fmt::format("{}:{:03}", tmp, tp.millitm); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); - return fmt::format("{}:{:03}", tmp, static_cast<int>(t.tv_usec / 1000)); -#endif + u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000; + return fmt::format("{}:{:03}", tmp, milliseconds); } // Returns a timestamp with decimals for precise time comparisons // ---------------- double Timer::GetDoubleTime() { -#ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); -#else - struct timeval t; - (void)gettimeofday(&t, nullptr); -#endif // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); + u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count()); + double ms = static_cast<u64>(GetTimeMs().count()) % 1000; // Remove a few years. We only really want enough seconds to make // sure that we are detecting actual actions, perhaps 60 seconds is @@ -196,12 +152,7 @@ double Timer::GetDoubleTime() { TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; -#ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; -#else - double ms = t.tv_usec / 1000000.0; -#endif + u32 Seconds = static_cast<u32>(TmpSeconds); double TmpTime = Seconds + ms; return TmpTime; diff --git a/src/common/timer.h b/src/common/timer.h index 78d37426b..27b521baa 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -4,6 +4,7 @@ #pragma once +#include <chrono> #include <string> #include "common/common_types.h" @@ -18,24 +19,22 @@ public: // The time difference is always returned in milliseconds, regardless of alternative internal // representation - u64 GetTimeDifference(); + std::chrono::milliseconds GetTimeDifference(); void AddTimeDifference(); - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); + static std::chrono::seconds GetTimeSinceJan1970(); + static std::chrono::seconds GetLocalTimeSinceJan1970(); static double GetDoubleTime(); static std::string GetTimeFormatted(); std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed(); + std::chrono::milliseconds GetTimeElapsed(); - static u32 GetTimeMs(); + static std::chrono::milliseconds GetTimeMs(); private: - u64 m_LastTime; - u64 m_StartTime; + std::chrono::milliseconds m_LastTime; + std::chrono::milliseconds m_StartTime; bool m_Running; }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2e2de59b1..3e13fc25b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -23,6 +23,8 @@ add_library(core STATIC file_sys/partition_filesystem.h file_sys/program_metadata.cpp file_sys/program_metadata.h + file_sys/romfs.cpp + file_sys/romfs.h file_sys/romfs_factory.cpp file_sys/romfs_factory.h file_sys/savedata_factory.cpp @@ -35,6 +37,8 @@ add_library(core STATIC file_sys/vfs_offset.h file_sys/vfs_real.cpp file_sys/vfs_real.h + file_sys/vfs_vector.cpp + file_sys/vfs_vector.h frontend/emu_window.cpp frontend/emu_window.h frontend/framebuffer_layout.cpp @@ -110,6 +114,12 @@ add_library(core STATIC hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h + hle/service/am/idle.cpp + hle/service/am/idle.h + hle/service/am/omm.cpp + hle/service/am/omm.h + hle/service/am/spsm.cpp + hle/service/am/spsm.h hle/service/aoc/aoc_u.cpp hle/service/aoc/aoc_u.h hle/service/apm/apm.cpp @@ -136,6 +146,10 @@ add_library(core STATIC hle/service/bcat/bcat.h hle/service/bcat/module.cpp hle/service/bcat/module.h + hle/service/btdrv/btdrv.cpp + hle/service/btdrv/btdrv.h + hle/service/btm/btm.cpp + hle/service/btm/btm.h hle/service/erpt/erpt.cpp hle/service/erpt/erpt.h hle/service/es/es.cpp @@ -152,24 +166,44 @@ add_library(core STATIC hle/service/filesystem/filesystem.h hle/service/filesystem/fsp_srv.cpp hle/service/filesystem/fsp_srv.h + hle/service/fgm/fgm.cpp + hle/service/fgm/fgm.h hle/service/friend/friend.cpp hle/service/friend/friend.h hle/service/friend/interface.cpp hle/service/friend/interface.h + hle/service/grc/grc.cpp + hle/service/grc/grc.h hle/service/hid/hid.cpp hle/service/hid/hid.h + hle/service/hid/irs.cpp + hle/service/hid/irs.h + hle/service/hid/xcd.cpp + hle/service/hid/xcd.h + hle/service/lbl/lbl.cpp + hle/service/lbl/lbl.h + hle/service/ldn/ldn.cpp + hle/service/ldn/ldn.h hle/service/ldr/ldr.cpp hle/service/ldr/ldr.h hle/service/lm/lm.cpp hle/service/lm/lm.h + hle/service/mii/mii.cpp + hle/service/mii/mii.h hle/service/mm/mm_u.cpp hle/service/mm/mm_u.h + hle/service/ncm/ncm.cpp + hle/service/ncm/ncm.h + hle/service/nfc/nfc.cpp + hle/service/nfc/nfc.h hle/service/nfp/nfp.cpp hle/service/nfp/nfp.h hle/service/nfp/nfp_user.cpp hle/service/nfp/nfp_user.h hle/service/nifm/nifm.cpp hle/service/nifm/nifm.h + hle/service/nim/nim.cpp + hle/service/nim/nim.h hle/service/ns/ns.cpp hle/service/ns/ns.h hle/service/ns/pl_u.cpp @@ -199,6 +233,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/pcie/pcie.cpp + hle/service/pcie/pcie.h hle/service/pctl/module.cpp hle/service/pctl/module.h hle/service/pctl/pctl.cpp @@ -225,6 +261,8 @@ add_library(core STATIC hle/service/sm/sm.h hle/service/sockets/bsd.cpp hle/service/sockets/bsd.h + hle/service/sockets/ethc.cpp + hle/service/sockets/ethc.h hle/service/sockets/nsd.cpp hle/service/sockets/nsd.h hle/service/sockets/sfdnsres.cpp @@ -251,6 +289,8 @@ add_library(core STATIC hle/service/vi/vi_s.h hle/service/vi/vi_u.cpp hle/service/vi/vi_u.h + hle/service/wlan/wlan.cpp + hle/service/wlan/wlan.h hw/hw.cpp hw/hw.h hw/lcd.cpp @@ -287,8 +327,8 @@ add_library(core STATIC create_target_directory_groups(core) -target_link_libraries(core PUBLIC common PRIVATE video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static unicorn) +target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static opus unicorn) if (ARCHITECTURE_x86_64) target_sources(core PRIVATE diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 57b8634b9..1d8c15d97 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -139,14 +139,12 @@ void ARM_Dynarmic::Step() { } ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index) - : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), - jit(MakeJit()), exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>( - exclusive_monitor)}, - core_index{core_index} { - ARM_Interface::ThreadContext ctx; + : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, + exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { + ThreadContext ctx; inner_unicorn.SaveContext(ctx); - LoadContext(ctx); PageTableChanged(); + LoadContext(ctx); } ARM_Dynarmic::~ARM_Dynarmic() = default; @@ -205,7 +203,7 @@ u64 ARM_Dynarmic::GetTlsAddress() const { return cb->tpidrro_el0; } -void ARM_Dynarmic::SetTlsAddress(u64 address) { +void ARM_Dynarmic::SetTlsAddress(VAddr address) { cb->tpidrro_el0 = address; } @@ -217,7 +215,7 @@ void ARM_Dynarmic::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { +void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); ctx.pc = jit->GetPC(); @@ -226,7 +224,7 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { ctx.fpscr = jit->GetFpcr(); } -void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { +void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { jit->SetRegisters(ctx.cpu_registers); jit->SetSP(ctx.sp); jit->SetPC(ctx.pc); diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index d6b20c047..61cb0bbe3 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -9,6 +9,7 @@ #include "core/file_sys/content_archive.h" #include "core/file_sys/vfs_offset.h" #include "core/loader/loader.h" +#include "romfs.h" namespace FileSys { @@ -46,21 +47,9 @@ struct PFS0Superblock { }; static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); -struct IVFCLevel { - u64_le offset; - u64_le size; - u32_le block_size; - u32_le reserved; -}; -static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); - struct RomFSSuperblock { NCASectionHeaderBlock header_block; - u32_le magic; - u32_le magic_number; - INSERT_PADDING_BYTES(8); - std::array<IVFCLevel, 6> levels; - INSERT_PADDING_BYTES(64); + IVFCHeader ivfc; }; static_assert(sizeof(RomFSSuperblock) == 0xE8, "RomFSSuperblock has incorrect size."); @@ -92,8 +81,8 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { const size_t romfs_offset = header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER + - sb.levels[IVFC_MAX_LEVEL - 1].offset; - const size_t romfs_size = sb.levels[IVFC_MAX_LEVEL - 1].size; + sb.ivfc.levels[IVFC_MAX_LEVEL - 1].offset; + const size_t romfs_size = sb.ivfc.levels[IVFC_MAX_LEVEL - 1].size; files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset)); romfs = files.back(); } else if (block.filesystem_type == NCASectionFilesystemType::PFS0) { diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 521e21078..47e032b19 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -97,9 +97,8 @@ void PartitionFilesystem::PrintDebugInfo() const { LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic); LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); for (u32 i = 0; i < pfs_header.num_entries; i++) { - LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, - pfs_files[i]->GetName(), pfs_files[i]->GetSize(), - dynamic_cast<OffsetVfsFile*>(pfs_files[i].get())->GetOffset()); + LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i, + pfs_files[i]->GetName(), pfs_files[i]->GetSize()); } } diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp new file mode 100644 index 000000000..ff3ddb29c --- /dev/null +++ b/src/core/file_sys/romfs.cpp @@ -0,0 +1,124 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/swap.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs_vector.h" + +namespace FileSys { + +constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF; + +struct TableLocation { + u64_le offset; + u64_le size; +}; +static_assert(sizeof(TableLocation) == 0x10, "TableLocation has incorrect size."); + +struct RomFSHeader { + u64_le header_size; + TableLocation directory_hash; + TableLocation directory_meta; + TableLocation file_hash; + TableLocation file_meta; + u64_le data_offset; +}; +static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); + +struct DirectoryEntry { + u32_le sibling; + u32_le child_dir; + u32_le child_file; + u32_le hash; + u32_le name_length; +}; +static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size."); + +struct FileEntry { + u32_le parent; + u32_le sibling; + u64_le offset; + u64_le size; + u32_le hash; + u32_le name_length; +}; +static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); + +template <typename Entry> +static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) { + Entry entry{}; + if (file->ReadObject(&entry, offset) != sizeof(Entry)) + return {}; + std::string string(entry.name_length, '\0'); + if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) + return {}; + return {entry, string}; +} + +void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset, + std::shared_ptr<VectorVfsDirectory> parent) { + while (true) { + auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); + + parent->AddFile(std::make_shared<OffsetVfsFile>( + file, entry.first.size, entry.first.offset + data_offset, entry.second, parent)); + + if (entry.first.sibling == ROMFS_ENTRY_EMPTY) + break; + + this_file_offset = entry.first.sibling; + } +} + +void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset, + u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) { + while (true) { + auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); + auto current = std::make_shared<VectorVfsDirectory>( + std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parent, entry.second); + + if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { + ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); + } + + if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { + ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, + current); + } + + parent->AddDirectory(current); + if (entry.first.sibling == ROMFS_ENTRY_EMPTY) + break; + this_dir_offset = entry.first.sibling; + } +} + +VirtualDir ExtractRomFS(VirtualFile file) { + RomFSHeader header{}; + if (file->ReadObject(&header) != sizeof(RomFSHeader)) + return nullptr; + + if (header.header_size != sizeof(RomFSHeader)) + return nullptr; + + const u64 file_offset = header.file_meta.offset; + const u64 dir_offset = header.directory_meta.offset + 4; + + const auto root = + std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, + file->GetContainingDirectory(), file->GetName()); + + ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root); + + VirtualDir out = std::move(root); + + while (out->GetSubdirectory("") != nullptr) + out = out->GetSubdirectory(""); + + return out; +} +} // namespace FileSys diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h new file mode 100644 index 000000000..03a876d22 --- /dev/null +++ b/src/core/file_sys/romfs.h @@ -0,0 +1,35 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include "common/common_funcs.h" +#include "common/swap.h" +#include "core/file_sys/vfs.h" + +namespace FileSys { + +struct IVFCLevel { + u64_le offset; + u64_le size; + u32_le block_size; + u32_le reserved; +}; +static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); + +struct IVFCHeader { + u32_le magic; + u32_le magic_number; + INSERT_PADDING_BYTES(8); + std::array<IVFCLevel, 6> levels; + INSERT_PADDING_BYTES(64); +}; +static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); + +// Converts a RomFS binary blob to VFS Filesystem +// Returns nullptr on failure +VirtualDir ExtractRomFS(VirtualFile file); + +} // namespace FileSys diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index b99a4fd5b..84a6a7397 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -46,6 +46,13 @@ size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) { return Write(data.data(), data.size(), offset); } +std::string VfsFile::GetFullPath() const { + if (GetContainingDirectory() == nullptr) + return "/" + GetName(); + + return GetContainingDirectory()->GetFullPath() + "/" + GetName(); +} + std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const { auto vec = FileUtil::SplitPathComponents(path); vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), @@ -243,6 +250,13 @@ bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize(); } +std::string VfsDirectory::GetFullPath() const { + if (IsRoot()) + return GetName(); + + return GetParentDirectory()->GetFullPath() + "/" + GetName(); +} + bool ReadOnlyVfsDirectory::IsWritable() const { return false; } @@ -270,4 +284,13 @@ bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { bool ReadOnlyVfsDirectory::Rename(std::string_view name) { return false; } + +bool VfsRawCopy(VirtualFile src, VirtualFile dest) { + if (src == nullptr || dest == nullptr) + return false; + if (!dest->Resize(src->GetSize())) + return false; + std::vector<u8> data = src->ReadAllBytes(); + return dest->WriteBytes(data, 0) == data.size(); +} } // namespace FileSys diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 4a13b8378..cf871edd6 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -113,6 +113,9 @@ struct VfsFile : NonCopyable { // Renames the file to name. Returns whether or not the operation was successsful. virtual bool Rename(std::string_view name) = 0; + + // Returns the full path of this file as a string, recursively + virtual std::string GetFullPath() const; }; // A class representing a directory in an abstract filesystem. @@ -213,6 +216,17 @@ struct VfsDirectory : NonCopyable { return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p)); } + bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function, + const std::string& file) { + auto file_p = GetFile(file); + if (file_p == nullptr) + return false; + return ReplaceFileWithSubdirectory(file_p, function(file_p)); + } + + // Returns the full path of this directory as a string, recursively + virtual std::string GetFullPath() const; + protected: // Backend for InterpretAsDirectory. // Removes all references to file and adds a reference to dir in the directory's implementation. @@ -230,4 +244,10 @@ struct ReadOnlyVfsDirectory : public VfsDirectory { bool DeleteFile(std::string_view name) override; bool Rename(std::string_view name) override; }; + +// A method that copies the raw data between two different implementations of VirtualFile. If you +// are using the same implementation, it is probably better to use the Copy method in the parent +// directory of src/dest. +bool VfsRawCopy(VirtualFile src, VirtualFile dest); + } // namespace FileSys diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index a40331cef..847cde2f5 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -10,8 +10,9 @@ namespace FileSys { OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_, - std::string name_) - : file(std::move(file_)), offset(offset_), size(size_), name(std::move(name_)) {} + std::string name_, VirtualDir parent_) + : file(file_), offset(offset_), size(size_), name(std::move(name_)), + parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} std::string OffsetVfsFile::GetName() const { return name.empty() ? file->GetName() : name; @@ -35,7 +36,7 @@ bool OffsetVfsFile::Resize(size_t new_size) { } std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const { - return file->GetContainingDirectory(); + return parent; } bool OffsetVfsFile::IsWritable() const { diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 4f471e3ba..235970dc5 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -17,7 +17,7 @@ namespace FileSys { // the size of this wrapper. struct OffsetVfsFile : public VfsFile { OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0, - std::string new_name = ""); + std::string new_name = "", VirtualDir new_parent = nullptr); std::string GetName() const override; size_t GetSize() const override; @@ -44,6 +44,7 @@ private: size_t offset; size_t size; std::string name; + VirtualDir parent; }; } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 9ce2e1efa..82d54da4a 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -195,6 +195,12 @@ bool RealVfsDirectory::Rename(std::string_view name) { return FileUtil::Rename(path, new_name); } +std::string RealVfsDirectory::GetFullPath() const { + auto out = path; + std::replace(out.begin(), out.end(), '\\', '/'); + return out; +} + bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { const auto iter = std::find(files.begin(), files.end(), file); if (iter == files.end()) diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 2151211c9..243d58576 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -41,7 +41,7 @@ private: // An implementation of VfsDirectory that represents a directory on the user's computer. struct RealVfsDirectory : public VfsDirectory { - RealVfsDirectory(const std::string& path, Mode perms); + RealVfsDirectory(const std::string& path, Mode perms = Mode::Read); std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; @@ -54,6 +54,7 @@ struct RealVfsDirectory : public VfsDirectory { bool DeleteSubdirectory(std::string_view name) override; bool DeleteFile(std::string_view name) override; bool Rename(std::string_view name) override; + std::string GetFullPath() const override; protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp new file mode 100644 index 000000000..4c6337e3a --- /dev/null +++ b/src/core/file_sys/vfs_vector.cpp @@ -0,0 +1,83 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include "core/file_sys/vfs_vector.h" + +namespace FileSys { +VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, + std::vector<VirtualDir> dirs_, VirtualDir parent_, + std::string name_) + : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)), + name(std::move(name_)) {} + +std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { + return files; +} + +std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const { + return dirs; +} + +bool VectorVfsDirectory::IsWritable() const { + return false; +} + +bool VectorVfsDirectory::IsReadable() const { + return true; +} + +std::string VectorVfsDirectory::GetName() const { + return name; +} +std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const { + return parent; +} + +template <typename T> +static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view name) { + auto iter = std::find_if(vec.begin(), vec.end(), [name](T e) { return e->GetName() == name; }); + if (iter == vec.end()) + return false; + auto old_size = vec.size(); + vec.erase(iter); + return true; +} + +bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) { + return FindAndRemoveVectorElement(dirs, name); +} + +bool VectorVfsDirectory::DeleteFile(std::string_view name) { + return FindAndRemoveVectorElement(files, name); +} + +bool VectorVfsDirectory::Rename(std::string_view name_) { + name = name_; + return true; +} + +std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) { + return nullptr; +} + +std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) { + return nullptr; +} + +void VectorVfsDirectory::AddFile(VirtualFile file) { + files.push_back(std::move(file)); +} + +void VectorVfsDirectory::AddDirectory(VirtualDir dir) { + dirs.push_back(std::move(dir)); +} + +bool VectorVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { + if (!DeleteFile(file->GetName())) + return false; + dirs.emplace_back(dir); + return true; +} +} // namespace FileSys diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h new file mode 100644 index 000000000..ba469647b --- /dev/null +++ b/src/core/file_sys/vfs_vector.h @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs.h" + +namespace FileSys { + +// An implementation of VfsDirectory that maintains two vectors for subdirectories and files. +// Vector data is supplied upon construction. +struct VectorVfsDirectory : public VfsDirectory { + explicit VectorVfsDirectory(std::vector<VirtualFile> files = {}, + std::vector<VirtualDir> dirs = {}, VirtualDir parent = nullptr, + std::string name = ""); + + std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; + std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; + bool IsWritable() const override; + bool IsReadable() const override; + std::string GetName() const override; + std::shared_ptr<VfsDirectory> GetParentDirectory() const override; + bool DeleteSubdirectory(std::string_view name) override; + bool DeleteFile(std::string_view name) override; + bool Rename(std::string_view name) override; + std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; + std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; + + virtual void AddFile(VirtualFile file); + virtual void AddDirectory(VirtualDir dir); + +protected: + bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; + +private: + std::vector<VirtualFile> files; + std::vector<VirtualDir> dirs; + + VirtualDir parent; + std::string name; +}; + +} // namespace FileSys diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 82d19cefc..c63f0ed90 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -32,13 +32,17 @@ public: return HANDLE_TYPE; } - ResetType reset_type; ///< The ResetType of this timer + ResetType GetResetType() const { + return reset_type; + } - bool signaled; ///< Whether the timer has been signaled or not - std::string name; ///< Name of timer (optional) + u64 GetInitialDelay() const { + return initial_delay; + } - u64 initial_delay; ///< The delay until the timer fires for the first time - u64 interval_delay; ///< The delay until the timer fires after the first time + u64 GetIntervalDelay() const { + return interval_delay; + } bool ShouldWait(Thread* thread) const override; void Acquire(Thread* thread) override; @@ -67,6 +71,14 @@ private: Timer(); ~Timer() override; + ResetType reset_type; ///< The ResetType of this timer + + u64 initial_delay; ///< The delay until the timer fires for the first time + u64 interval_delay; ///< The delay until the timer fires after the first time + + bool signaled; ///< Whether the timer has been signaled or not + std::string name; ///< Name of timer (optional) + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle callback_handle; }; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 97ef07bf9..94d2a973d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -11,6 +11,9 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/idle.h" +#include "core/hle/service/am/omm.h" +#include "core/hle/service/am/spsm.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -689,6 +692,9 @@ void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); + std::make_shared<IdleSys>()->InstallAsService(service_manager); + std::make_shared<OMM>()->InstallAsService(service_manager); + std::make_shared<SPSM>()->InstallAsService(service_manager); } IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp new file mode 100644 index 000000000..af46e9494 --- /dev/null +++ b/src/core/hle/service/am/idle.cpp @@ -0,0 +1,24 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/idle.h" + +namespace Service::AM { + +IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetAutoPowerDownEvent"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h new file mode 100644 index 000000000..1eb68d2c9 --- /dev/null +++ b/src/core/hle/service/am/idle.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class IdleSys final : public ServiceFramework<IdleSys> { +public: + explicit IdleSys(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp new file mode 100644 index 000000000..447fe8669 --- /dev/null +++ b/src/core/hle/service/am/omm.cpp @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/omm.h" + +namespace Service::AM { + +OMM::OMM() : ServiceFramework{"omm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetOperationMode"}, + {1, nullptr, "GetOperationModeChangeEvent"}, + {2, nullptr, "EnableAudioVisual"}, + {3, nullptr, "DisableAudioVisual"}, + {4, nullptr, "EnterSleepAndWait"}, + {5, nullptr, "GetCradleStatus"}, + {6, nullptr, "FadeInDisplay"}, + {7, nullptr, "FadeOutDisplay"}, + {8, nullptr, "Unknown1"}, + {9, nullptr, "Unknown2"}, + {10, nullptr, "Unknown3"}, + {11, nullptr, "Unknown4"}, + {12, nullptr, "Unknown5"}, + {13, nullptr, "Unknown6"}, + {14, nullptr, "Unknown7"}, + {15, nullptr, "Unknown8"}, + {16, nullptr, "Unknown9"}, + {17, nullptr, "Unknown10"}, + {18, nullptr, "Unknown11"}, + {19, nullptr, "Unknown12"}, + {20, nullptr, "Unknown13"}, + {21, nullptr, "Unknown14"}, + {22, nullptr, "Unknown15"}, + {23, nullptr, "Unknown16"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h new file mode 100644 index 000000000..49e5d331c --- /dev/null +++ b/src/core/hle/service/am/omm.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class OMM final : public ServiceFramework<OMM> { +public: + explicit OMM(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp new file mode 100644 index 000000000..a05d433d0 --- /dev/null +++ b/src/core/hle/service/am/spsm.cpp @@ -0,0 +1,30 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/am/spsm.h" + +namespace Service::AM { + +SPSM::SPSM() : ServiceFramework{"spsm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetState"}, + {1, nullptr, "SleepSystemAndWaitAwake"}, + {2, nullptr, "Unknown1"}, + {3, nullptr, "Unknown2"}, + {4, nullptr, "GetNotificationMessageEventHandle"}, + {5, nullptr, "Unknown3"}, + {6, nullptr, "Unknown4"}, + {7, nullptr, "Unknown5"}, + {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"}, + {9, nullptr, "ChangeHomeButtonLongPressingTime"}, + {10, nullptr, "Unknown6"}, + {11, nullptr, "Unknown7"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h new file mode 100644 index 000000000..57dde62e1 --- /dev/null +++ b/src/core/hle/service/am/spsm.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::AM { + +class SPSM final : public ServiceFramework<SPSM> { +public: + explicit SPSM(); +}; + +} // namespace Service::AM diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 1dcd84d98..ab37c2a69 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -5,8 +5,7 @@ #include <array> #include <vector> #include "common/logging/log.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" @@ -14,17 +13,21 @@ namespace Service::Audio { -/// Switch sample rate frequency -constexpr u32 sample_rate{48000}; -/// TODO(st4rk): dynamic number of channels, as I think Switch has support -/// to more audio channels (probably when Docked I guess) -constexpr u32 audio_channels{2}; -/// TODO(st4rk): find a proper value for the audio_ticks -constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 500)}; +namespace ErrCodes { +enum { + ErrorUnknown = 2, + BufferCountExceeded = 8, +}; +} + +constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; +constexpr int DefaultSampleRate{48000}; class IAudioOut final : public ServiceFramework<IAudioOut> { public: - IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) { + IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) + : ServiceFramework("IAudioOut"), audio_params(audio_params), audio_core(audio_core) { + static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, @@ -32,66 +35,65 @@ public: {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"}, {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"}, - {6, nullptr, "ContainsAudioOutBuffer"}, + {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"}, {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"}, {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, - {9, nullptr, "GetAudioOutBufferCount"}, + {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, {10, nullptr, "GetAudioOutPlayedSampleCount"}, {11, nullptr, "FlushAudioOutBuffers"}, }; RegisterHandlers(functions); // This is the event handle used to check if the audio buffer was released - buffer_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent"); - - // Register event callback to update the Audio Buffer - audio_event = CoreTiming::RegisterEvent( - "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) { - UpdateAudioBuffersCallback(); - CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event); - }); - - // Start the audio event - CoreTiming::ScheduleEvent(audio_ticks, audio_event); - } + buffer_event = Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); - ~IAudioOut() { - CoreTiming::UnscheduleEvent(audio_event, 0); + stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, + [=]() { buffer_event->Signal(); }); } private: + struct AudioBuffer { + u64_le next; + u64_le buffer; + u64_le buffer_capacity; + u64_le buffer_size; + u64_le offset; + }; + static_assert(sizeof(AudioBuffer) == 0x28, "AudioBuffer is an invalid size"); + void GetAudioOutState(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast<u32>(audio_out_state)); + rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); } void StartAudioOut(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "called"); + + if (stream->IsPlaying()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown)); + return; + } - // Start audio - audio_out_state = AudioState::Started; + audio_core.StartStream(stream); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void StopAudioOut(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); - - // Stop audio - audio_out_state = AudioState::Stopped; + LOG_DEBUG(Service_Audio, "called"); - queue_keys.clear(); + audio_core.StopStream(stream); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); @@ -99,101 +101,107 @@ private: } void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "(STUBBED) called {}", ctx.Description()); IPC::RequestParser rp{ctx}; - const u64 key{rp.Pop<u64>()}; - queue_keys.insert(queue_keys.begin(), key); + const auto& input_buffer{ctx.ReadBuffer()}; + ASSERT_MSG(input_buffer.size() == sizeof(AudioBuffer), + "AudioBuffer input is an invalid size!"); + AudioBuffer audio_buffer{}; + std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer)); + const u64 tag{rp.Pop<u64>()}; + + std::vector<u8> data(audio_buffer.buffer_size); + Memory::ReadBlock(audio_buffer.buffer, data.data(), data.size()); + + if (!audio_core.QueueBuffer(stream, tag, std::move(data))) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded)); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); - - // TODO(st4rk): This is how libtransistor currently implements the - // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address - // is used to know which buffer should be filled with data and send again to the service - // through AppendAudioOutBuffer. Check if this is the proper way to do it. - u64 key{0}; - - if (queue_keys.size()) { - key = queue_keys.back(); - queue_keys.pop_back(); - } + LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); + IPC::RequestParser rp{ctx}; + const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; + const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; - ctx.WriteBuffer(&key, sizeof(u64)); + std::vector<u64> tags{released_buffers}; + tags.resize(max_count); + ctx.WriteBuffer(tags); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - // TODO(st4rk): This might be the total of released buffers, needs to be verified on - // hardware - rb.Push<u32>(static_cast<u32>(queue_keys.size())); + rb.Push<u32>(static_cast<u32>(released_buffers.size())); } - void UpdateAudioBuffersCallback() { - if (audio_out_state != AudioState::Started) { - return; - } - - if (queue_keys.empty()) { - return; - } + void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Audio, "called"); + IPC::RequestParser rp{ctx}; + const u64 tag{rp.Pop<u64>()}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(stream->ContainsBuffer(tag)); + } - buffer_event->Signal(); + void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Audio, "called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u32>(stream->GetQueueSize())); } - enum class AudioState : u32 { - Started, - Stopped, - }; + AudioCore::AudioOut& audio_core; + AudioCore::StreamPtr stream; - /// This is used to trigger the audio event callback that is going to read the samples from the - /// audio_buffer list and enqueue the samples using the sink (audio_core). - CoreTiming::EventType* audio_event; + AudoutParams audio_params{}; /// This is the evend handle used to check if the audio buffer was released Kernel::SharedPtr<Kernel::Event> buffer_event; - - /// (st4rk): This is just a temporary workaround for the future implementation. Libtransistor - /// uses the key as an address in the App, so we need to return when the - /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because - /// libtransistor uses the key returned as an pointer. - std::vector<u64> queue_keys; - - AudioState audio_out_state; }; void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "called"); IPC::RequestParser rp{ctx}; - constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; - ctx.WriteBuffer(audio_interface); + ctx.WriteBuffer(DefaultDevice); IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); rb.Push(RESULT_SUCCESS); - // TODO(st4rk): We're currently returning only one audio interface (stringlist size). However, - // it's highly possible to have more than one interface (despite that libtransistor requires - // only one). - rb.Push<u32>(1); + rb.Push<u32>(1); // Amount of audio devices } void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + LOG_DEBUG(Service_Audio, "called"); - if (!audio_out_interface) { - audio_out_interface = std::make_shared<IAudioOut>(); + ctx.WriteBuffer(DefaultDevice); + IPC::RequestParser rp{ctx}; + auto params{rp.PopRaw<AudoutParams>()}; + if (params.channel_count <= 2) { + // Mono does not exist for audout + params.channel_count = 2; + } else { + params.channel_count = 6; } + if (!params.sample_rate) { + params.sample_rate = DefaultSampleRate; + } + + // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl + // will likely need to be updated as well. + ASSERT_MSG(!audio_out_interface, "Unimplemented"); + audio_out_interface = std::make_shared<IAudioOut>(std::move(params), *audio_core); IPC::ResponseBuilder rb{ctx, 6, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(sample_rate); - rb.Push<u32>(audio_channels); + rb.Push<u32>(DefaultSampleRate); + rb.Push<u32>(params.channel_count); rb.Push<u32>(static_cast<u32>(PcmFormat::Int16)); - rb.Push<u32>(0); // This field is unknown + rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); } @@ -203,6 +211,7 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") { {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}}; RegisterHandlers(functions); + audio_core = std::make_unique<AudioCore::AudioOut>(); } } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index 847d86aa6..e5c2184d5 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -4,6 +4,7 @@ #pragma once +#include "audio_core/audio_out.h" #include "core/hle/service/service.h" namespace Kernel { @@ -12,6 +13,18 @@ class HLERequestContext; namespace Service::Audio { +struct AudoutParams { + s32_le sample_rate; + u16_le channel_count; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); + +enum class AudioState : u32 { + Started, + Stopped, +}; + class IAudioOut; class AudOutU final : public ServiceFramework<AudOutU> { @@ -21,6 +34,7 @@ public: private: std::shared_ptr<IAudioOut> audio_out_interface; + std::unique_ptr<AudioCore::AudioOut> audio_core; void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 844df382c..371cd4997 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> +#include <opus.h> #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -9,19 +11,142 @@ namespace Service::Audio { +struct OpusDeleter { + void operator()(void* ptr) const { + operator delete(ptr); + } +}; + +class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { +public: + IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoder, OpusDeleter> decoder, u32 sample_rate, + u32 channel_count) + : ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)), + sample_rate(sample_rate), channel_count(channel_count) { + static const FunctionInfo functions[] = { + {0, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, + {1, nullptr, "SetContext"}, + {2, nullptr, "DecodeInterleavedForMultiStream"}, + {3, nullptr, "SetContextForMultiStream"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + }; + RegisterHandlers(functions); + } + +private: + void DecodeInterleaved(Kernel::HLERequestContext& ctx) { + u32 consumed = 0; + u32 sample_count = 0; + std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); + if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(ogniK): Use correct error code + rb.Push(ResultCode(-1)); + return; + } + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(consumed); + rb.Push<u32>(sample_count); + ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); + } + + bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, + std::vector<opus_int16>& output) { + size_t raw_output_sz = output.size() * sizeof(opus_int16); + if (sizeof(OpusHeader) > input.size()) + return false; + OpusHeader hdr{}; + std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); + if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { + return false; + } + auto frame = input.data() + sizeof(OpusHeader); + auto decoded_sample_count = opus_packet_get_nb_samples( + frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), + static_cast<opus_int32>(sample_rate)); + if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) + return false; + auto out_sample_count = + opus_decode(decoder.get(), frame, hdr.sz, output.data(), + (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); + if (out_sample_count < 0) + return false; + sample_count = out_sample_count; + consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); + return true; + } + + struct OpusHeader { + u32_be sz; // Needs to be BE for some odd reason + INSERT_PADDING_WORDS(1); + }; + static_assert(sizeof(OpusHeader) == 0x8, "OpusHeader is an invalid size"); + + std::unique_ptr<OpusDecoder, OpusDeleter> decoder; + u32 sample_rate; + u32 channel_count; +}; + +static size_t WorkerBufferSize(u32 channel_count) { + ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); + return opus_decoder_get_size(static_cast<int>(channel_count)); +} + void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + auto sample_rate = rp.Pop<u32>(); + auto channel_count = rp.Pop<u32>(); + ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || + sample_rate == 12000 || sample_rate == 8000, + "Invalid sample rate"); + ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); + u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); + LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(0x4000); + rb.Push<u32>(worker_buffer_sz); +} + +void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto sample_rate = rp.Pop<u32>(); + auto channel_count = rp.Pop<u32>(); + auto buffer_sz = rp.Pop<u32>(); + LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, + channel_count, buffer_sz); + ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || + sample_rate == 12000 || sample_rate == 8000, + "Invalid sample rate"); + ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); + + size_t worker_sz = WorkerBufferSize(channel_count); + ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); + std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ + static_cast<OpusDecoder*>(operator new(worker_sz))}; + if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { + IPC::ResponseBuilder rb{ctx, 2}; + // TODO(ogniK): Use correct error code + rb.Push(ResultCode(-1)); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHardwareOpusDecoderManager>(std::move(decoder), sample_rate, + channel_count); } HwOpus::HwOpus() : ServiceFramework("hwopus") { static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, + {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"}, {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, - {2, nullptr, "InitializeMultiStream"}, - {3, nullptr, "GetWorkBufferSizeMultiStream"}, + {2, nullptr, "OpenOpusDecoderForMultiStream"}, + {3, nullptr, "GetWorkBufferSizeForMultiStream"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h index 090b8c825..5258d59f3 100644 --- a/src/core/hle/service/audio/hwopus.h +++ b/src/core/hle/service/audio/hwopus.h @@ -14,6 +14,7 @@ public: ~HwOpus() = default; private: + void OpenOpusDecoder(Kernel::HLERequestContext& ctx); void GetWorkBufferSize(Kernel::HLERequestContext& ctx); }; diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp new file mode 100644 index 000000000..d0a15cc4c --- /dev/null +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -0,0 +1,72 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/btdrv/btdrv.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::BtDrv { + +class BtDrv final : public ServiceFramework<BtDrv> { +public: + explicit BtDrv() : ServiceFramework{"btdrv"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown"}, + {1, nullptr, "Init"}, + {2, nullptr, "Enable"}, + {3, nullptr, "Disable"}, + {4, nullptr, "CleanupAndShutdown"}, + {5, nullptr, "GetAdapterProperties"}, + {6, nullptr, "GetAdapterProperty"}, + {7, nullptr, "SetAdapterProperty"}, + {8, nullptr, "StartDiscovery"}, + {9, nullptr, "CancelDiscovery"}, + {10, nullptr, "CreateBond"}, + {11, nullptr, "RemoveBond"}, + {12, nullptr, "CancelBond"}, + {13, nullptr, "PinReply"}, + {14, nullptr, "SspReply"}, + {15, nullptr, "Unknown2"}, + {16, nullptr, "InitInterfaces"}, + {17, nullptr, "HidHostInterface_Connect"}, + {18, nullptr, "HidHostInterface_Disconnect"}, + {19, nullptr, "HidHostInterface_SendData"}, + {20, nullptr, "HidHostInterface_SendData2"}, + {21, nullptr, "HidHostInterface_SetReport"}, + {22, nullptr, "HidHostInterface_GetReport"}, + {23, nullptr, "HidHostInterface_WakeController"}, + {24, nullptr, "HidHostInterface_AddPairedDevice"}, + {25, nullptr, "HidHostInterface_GetPairedDevice"}, + {26, nullptr, "HidHostInterface_CleanupAndShutdown"}, + {27, nullptr, "Unknown3"}, + {28, nullptr, "ExtInterface_SetTSI"}, + {29, nullptr, "ExtInterface_SetBurstMode"}, + {30, nullptr, "ExtInterface_SetZeroRetran"}, + {31, nullptr, "ExtInterface_SetMcMode"}, + {32, nullptr, "ExtInterface_StartLlrMode"}, + {33, nullptr, "ExtInterface_ExitLlrMode"}, + {34, nullptr, "ExtInterface_SetRadio"}, + {35, nullptr, "ExtInterface_SetVisibility"}, + {36, nullptr, "Unknown4"}, + {37, nullptr, "Unknown5"}, + {38, nullptr, "HidHostInterface_GetLatestPlr"}, + {39, nullptr, "ExtInterface_GetPendingConnections"}, + {40, nullptr, "HidHostInterface_GetChannelMap"}, + {41, nullptr, "SetIsBluetoothBoostEnabled"}, + {42, nullptr, "GetIsBluetoothBoostEnabled"}, + {43, nullptr, "SetIsBluetoothAfhEnabled"}, + {44, nullptr, "GetIsBluetoothAfhEnabled"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<BtDrv>()->InstallAsService(sm); +} + +} // namespace Service::BtDrv diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h new file mode 100644 index 000000000..164e56f43 --- /dev/null +++ b/src/core/hle/service/btdrv/btdrv.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::BtDrv { + +/// Registers all BtDrv services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::BtDrv diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp new file mode 100644 index 000000000..b949bfabd --- /dev/null +++ b/src/core/hle/service/btm/btm.cpp @@ -0,0 +1,121 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/btm/btm.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::BTM { + +class BTM final : public ServiceFramework<BTM> { +public: + explicit BTM() : ServiceFramework{"btm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "RegisterSystemEventForConnectedDeviceConditionImpl"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "RegisterSystemEventForRegisteredDeviceInfoImpl"}, + {9, nullptr, "Unknown8"}, + {10, nullptr, "Unknown9"}, + {11, nullptr, "Unknown10"}, + {12, nullptr, "Unknown11"}, + {13, nullptr, "Unknown12"}, + {14, nullptr, "EnableRadioImpl"}, + {15, nullptr, "DisableRadioImpl"}, + {16, nullptr, "Unknown13"}, + {17, nullptr, "Unknown14"}, + {18, nullptr, "Unknown15"}, + {19, nullptr, "Unknown16"}, + {20, nullptr, "Unknown17"}, + {21, nullptr, "Unknown18"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class BTM_DBG final : public ServiceFramework<BTM_DBG> { +public: + explicit BTM_DBG() : ServiceFramework{"btm:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RegisterSystemEventForDiscoveryImpl"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, + {6, nullptr, "Unknown6"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { +public: + explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "StartGamepadPairingImpl"}, + {1, nullptr, "CancelGamepadPairingImpl"}, + {2, nullptr, "ClearGamepadPairingDatabaseImpl"}, + {3, nullptr, "GetPairedGamepadCountImpl"}, + {4, nullptr, "EnableRadioImpl"}, + {5, nullptr, "DisableRadioImpl"}, + {6, nullptr, "GetRadioOnOffImpl"}, + {7, nullptr, "AcquireRadioEventImpl"}, + {8, nullptr, "AcquireGamepadPairingEventImpl"}, + {9, nullptr, "IsGamepadPairingStartedImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class BTM_SYS final : public ServiceFramework<BTM_SYS> { +public: + explicit BTM_SYS() : ServiceFramework{"btm:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &BTM_SYS::GetCoreImpl, "GetCoreImpl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetCoreImpl(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IBtmSystemCore>(); + + LOG_DEBUG(Service_BTM, "called"); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<BTM>()->InstallAsService(sm); + std::make_shared<BTM_DBG>()->InstallAsService(sm); + std::make_shared<BTM_SYS>()->InstallAsService(sm); +} + +} // namespace Service::BTM diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h new file mode 100644 index 000000000..e6425a7e3 --- /dev/null +++ b/src/core/hle/service/btm/btm.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::BTM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::BTM diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp new file mode 100644 index 000000000..566fbf924 --- /dev/null +++ b/src/core/hle/service/fgm/fgm.cpp @@ -0,0 +1,75 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/fgm/fgm.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::FGM { + +class IRequest final : public ServiceFramework<IRequest> { +public: + explicit IRequest() : ServiceFramework{"IRequest"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Set"}, + {2, nullptr, "Get"}, + {3, nullptr, "Cancel"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class FGM final : public ServiceFramework<FGM> { +public: + explicit FGM(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &FGM::Initialize, "Initialize"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Initialize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IRequest>(); + + LOG_DEBUG(Service_FGM, "called"); + } +}; + +class FGM_DBG final : public ServiceFramework<FGM_DBG> { +public: + explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Read"}, + {2, nullptr, "Cancel"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<FGM>("fgm")->InstallAsService(sm); + std::make_shared<FGM>("fgm:0")->InstallAsService(sm); + std::make_shared<FGM>("fgm:9")->InstallAsService(sm); + std::make_shared<FGM_DBG>()->InstallAsService(sm); +} + +} // namespace Service::FGM diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h new file mode 100644 index 000000000..e59691264 --- /dev/null +++ b/src/core/hle/service/fgm/fgm.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::FGM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::FGM diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp new file mode 100644 index 000000000..24910ac6c --- /dev/null +++ b/src/core/hle/service/grc/grc.cpp @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/grc/grc.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::GRC { + +class GRC final : public ServiceFramework<GRC> { +public: + explicit GRC() : ServiceFramework{"grc:c"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "OpenContinuousRecorder"}, + {2, nullptr, "OpenGameMovieTrimmer"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<GRC>()->InstallAsService(sm); +} + +} // namespace Service::GRC diff --git a/src/core/hle/service/grc/grc.h b/src/core/hle/service/grc/grc.h new file mode 100644 index 000000000..e0d29e70d --- /dev/null +++ b/src/core/hle/service/grc/grc.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::GRC { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::GRC diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9a02ba686..ed53f96c5 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -14,6 +14,8 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/hid/irs.h" +#include "core/hle/service/hid/xcd.h" #include "core/hle/service/service.h" namespace Service::HID { @@ -324,7 +326,7 @@ public: {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, {80, nullptr, "GetGyroscopeZeroDriftMode"}, {81, nullptr, "ResetGyroscopeZeroDriftMode"}, - {82, nullptr, "IsSixAxisSensorAtRest"}, + {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, {91, nullptr, "ActivateGesture"}, {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, @@ -341,7 +343,7 @@ public: "SetNpadJoyAssignmentModeSingleByDefault"}, {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, - {125, nullptr, "MergeSingleJoyAsDualJoy"}, + {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, {126, nullptr, "StartLrAssignmentMode"}, {127, nullptr, "StopLrAssignmentMode"}, {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, @@ -453,6 +455,14 @@ private: LOG_WARNING(Service_HID, "(STUBBED) called"); } + void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. + rb.Push(true); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -528,6 +538,12 @@ private: LOG_WARNING(Service_HID, "(STUBBED) called"); } + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service_HID, "(STUBBED) called"); + } + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -555,10 +571,233 @@ private: } }; +class HidDbg final : public ServiceFramework<HidDbg> { +public: + explicit HidDbg() : ServiceFramework{"hid:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "DeactivateDebugPad"}, + {1, nullptr, "SetDebugPadAutoPilotState"}, + {2, nullptr, "UnsetDebugPadAutoPilotState"}, + {10, nullptr, "DeactivateTouchScreen"}, + {11, nullptr, "SetTouchScreenAutoPilotState"}, + {12, nullptr, "UnsetTouchScreenAutoPilotState"}, + {20, nullptr, "DeactivateMouse"}, + {21, nullptr, "SetMouseAutoPilotState"}, + {22, nullptr, "UnsetMouseAutoPilotState"}, + {30, nullptr, "DeactivateKeyboard"}, + {31, nullptr, "SetKeyboardAutoPilotState"}, + {32, nullptr, "UnsetKeyboardAutoPilotState"}, + {50, nullptr, "DeactivateXpad"}, + {51, nullptr, "SetXpadAutoPilotState"}, + {52, nullptr, "UnsetXpadAutoPilotState"}, + {60, nullptr, "DeactivateJoyXpad"}, + {91, nullptr, "DeactivateGesture"}, + {110, nullptr, "DeactivateHomeButton"}, + {111, nullptr, "SetHomeButtonAutoPilotState"}, + {112, nullptr, "UnsetHomeButtonAutoPilotState"}, + {120, nullptr, "DeactivateSleepButton"}, + {121, nullptr, "SetSleepButtonAutoPilotState"}, + {122, nullptr, "UnsetSleepButtonAutoPilotState"}, + {123, nullptr, "DeactivateInputDetector"}, + {130, nullptr, "DeactivateCaptureButton"}, + {131, nullptr, "SetCaptureButtonAutoPilotState"}, + {132, nullptr, "UnsetCaptureButtonAutoPilotState"}, + {133, nullptr, "SetShiftAccelerometerCalibrationValue"}, + {134, nullptr, "GetShiftAccelerometerCalibrationValue"}, + {135, nullptr, "SetShiftGyroscopeCalibrationValue"}, + {136, nullptr, "GetShiftGyroscopeCalibrationValue"}, + {140, nullptr, "DeactivateConsoleSixAxisSensor"}, + {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"}, + {142, nullptr, "DeactivateSevenSixAxisSensor"}, + {201, nullptr, "ActivateFirmwareUpdate"}, + {202, nullptr, "DeactivateFirmwareUpdate"}, + {203, nullptr, "StartFirmwareUpdate"}, + {204, nullptr, "GetFirmwareUpdateStage"}, + {205, nullptr, "GetFirmwareVersion"}, + {206, nullptr, "GetDestinationFirmwareVersion"}, + {207, nullptr, "DiscardFirmwareInfoCacheForRevert"}, + {208, nullptr, "StartFirmwareUpdateForRevert"}, + {209, nullptr, "GetAvailableFirmwareVersionForRevert"}, + {210, nullptr, "IsFirmwareUpdatingDevice"}, + {221, nullptr, "UpdateControllerColor"}, + {222, nullptr, "ConnectUsbPadsAsync"}, + {223, nullptr, "DisconnectUsbPadsAsync"}, + {224, nullptr, "UpdateDesignInfo"}, + {225, nullptr, "GetUniquePadDriverState"}, + {226, nullptr, "GetSixAxisSensorDriverStates"}, + {301, nullptr, "GetAbstractedPadHandles"}, + {302, nullptr, "GetAbstractedPadState"}, + {303, nullptr, "GetAbstractedPadsState"}, + {321, nullptr, "SetAutoPilotVirtualPadState"}, + {322, nullptr, "UnsetAutoPilotVirtualPadState"}, + {323, nullptr, "UnsetAllAutoPilotVirtualPadState"}, + {350, nullptr, "AddRegisteredDevice"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class HidSys final : public ServiceFramework<HidSys> { +public: + explicit HidSys() : ServiceFramework{"hid:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {31, nullptr, "SendKeyboardLockKeyEvent"}, + {101, nullptr, "AcquireHomeButtonEventHandle"}, + {111, nullptr, "ActivateHomeButton"}, + {121, nullptr, "AcquireSleepButtonEventHandle"}, + {131, nullptr, "ActivateSleepButton"}, + {141, nullptr, "AcquireCaptureButtonEventHandle"}, + {151, nullptr, "ActivateCaptureButton"}, + {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, + {211, nullptr, "GetNpadsWithNfc"}, + {212, nullptr, "AcquireNfcActivateEventHandle"}, + {213, nullptr, "ActivateNfc"}, + {214, nullptr, "GetXcdHandleForNpadWithNfc"}, + {215, nullptr, "IsNfcActivated"}, + {230, nullptr, "AcquireIrSensorEventHandle"}, + {231, nullptr, "ActivateIrSensor"}, + {301, nullptr, "ActivateNpadSystem"}, + {303, nullptr, "ApplyNpadSystemCommonPolicy"}, + {304, nullptr, "EnableAssigningSingleOnSlSrPress"}, + {305, nullptr, "DisableAssigningSingleOnSlSrPress"}, + {306, nullptr, "GetLastActiveNpad"}, + {307, nullptr, "GetNpadSystemExtStyle"}, + {308, nullptr, "ApplyNpadSystemCommonPolicyFull"}, + {309, nullptr, "GetNpadFullKeyGripColor"}, + {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, + {321, nullptr, "GetUniquePadsFromNpad"}, + {322, nullptr, "GetIrSensorState"}, + {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, + {500, nullptr, "SetAppletResourceUserId"}, + {501, nullptr, "RegisterAppletResourceUserId"}, + {502, nullptr, "UnregisterAppletResourceUserId"}, + {503, nullptr, "EnableAppletToGetInput"}, + {504, nullptr, "SetAruidValidForVibration"}, + {505, nullptr, "EnableAppletToGetSixAxisSensor"}, + {510, nullptr, "SetVibrationMasterVolume"}, + {511, nullptr, "GetVibrationMasterVolume"}, + {512, nullptr, "BeginPermitVibrationSession"}, + {513, nullptr, "EndPermitVibrationSession"}, + {520, nullptr, "EnableHandheldHids"}, + {521, nullptr, "DisableHandheldHids"}, + {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, + {541, nullptr, "GetPlayReportControllerUsages"}, + {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, + {543, nullptr, "GetRegisteredDevicesOld"}, + {544, nullptr, "AcquireConnectionTriggerTimeoutEvent"}, + {545, nullptr, "SendConnectionTrigger"}, + {546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"}, + {547, nullptr, "GetAllowedBluetoothLinksCount"}, + {548, nullptr, "GetRegisteredDevices"}, + {700, nullptr, "ActivateUniquePad"}, + {702, nullptr, "AcquireUniquePadConnectionEventHandle"}, + {703, nullptr, "GetUniquePadIds"}, + {751, nullptr, "AcquireJoyDetachOnBluetoothOffEventHandle"}, + {800, nullptr, "ListSixAxisSensorHandles"}, + {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"}, + {802, nullptr, "ResetSixAxisSensorCalibrationValues"}, + {803, nullptr, "StartSixAxisSensorUserCalibration"}, + {804, nullptr, "CancelSixAxisSensorUserCalibration"}, + {805, nullptr, "GetUniquePadBluetoothAddress"}, + {806, nullptr, "DisconnectUniquePad"}, + {807, nullptr, "GetUniquePadType"}, + {808, nullptr, "GetUniquePadInterface"}, + {809, nullptr, "GetUniquePadSerialNumber"}, + {810, nullptr, "GetUniquePadControllerNumber"}, + {811, nullptr, "GetSixAxisSensorUserCalibrationStage"}, + {821, nullptr, "StartAnalogStickManualCalibration"}, + {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"}, + {823, nullptr, "CancelAnalogStickManualCalibration"}, + {824, nullptr, "ResetAnalogStickManualCalibration"}, + {825, nullptr, "GetAnalogStickState"}, + {826, nullptr, "GetAnalogStickManualCalibrationStage"}, + {827, nullptr, "IsAnalogStickButtonPressed"}, + {828, nullptr, "IsAnalogStickInReleasePosition"}, + {829, nullptr, "IsAnalogStickInCircumference"}, + {850, nullptr, "IsUsbFullKeyControllerEnabled"}, + {851, nullptr, "EnableUsbFullKeyController"}, + {852, nullptr, "IsUsbConnected"}, + {900, nullptr, "ActivateInputDetector"}, + {901, nullptr, "NotifyInputDetector"}, + {1000, nullptr, "InitializeFirmwareUpdate"}, + {1001, nullptr, "GetFirmwareVersion"}, + {1002, nullptr, "GetAvailableFirmwareVersion"}, + {1003, nullptr, "IsFirmwareUpdateAvailable"}, + {1004, nullptr, "CheckFirmwareUpdateRequired"}, + {1005, nullptr, "StartFirmwareUpdate"}, + {1006, nullptr, "AbortFirmwareUpdate"}, + {1007, nullptr, "GetFirmwareUpdateState"}, + {1008, nullptr, "ActivateAudioControl"}, + {1009, nullptr, "AcquireAudioControlEventHandle"}, + {1010, nullptr, "GetAudioControlStates"}, + {1011, nullptr, "DeactivateAudioControl"}, + {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"}, + {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"}, + {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, + {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, + {1100, nullptr, "GetHidbusSystemServiceObject"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class HidTmp final : public ServiceFramework<HidTmp> { +public: + explicit HidTmp() : ServiceFramework{"hid:tmp"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class HidBus final : public ServiceFramework<HidBus> { +public: + explicit HidBus() : ServiceFramework{"hidbus"} { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "GetBusHandle"}, + {2, nullptr, "IsExternalDeviceConnected"}, + {3, nullptr, "Initialize"}, + {4, nullptr, "Finalize"}, + {5, nullptr, "EnableExternalDevice"}, + {6, nullptr, "GetExternalDeviceId"}, + {7, nullptr, "SendCommandAsync"}, + {8, nullptr, "GetSendCommandAsynceResult"}, + {9, nullptr, "SetEventForSendCommandAsycResult"}, + {10, nullptr, "GetSharedMemoryHandle"}, + {11, nullptr, "EnableJoyPollingReceiveMode"}, + {12, nullptr, "DisableJoyPollingReceiveMode"}, + {13, nullptr, "GetPollingData"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + void ReloadInputDevices() {} void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<Hid>()->InstallAsService(service_manager); + std::make_shared<HidBus>()->InstallAsService(service_manager); + std::make_shared<HidDbg>()->InstallAsService(service_manager); + std::make_shared<HidSys>()->InstallAsService(service_manager); + std::make_shared<HidTmp>()->InstallAsService(service_manager); + + std::make_shared<IRS>()->InstallAsService(service_manager); + std::make_shared<IRS_SYS>()->InstallAsService(service_manager); + + std::make_shared<XCD_SYS>()->InstallAsService(service_manager); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp new file mode 100644 index 000000000..aaf311912 --- /dev/null +++ b/src/core/hle/service/hid/irs.cpp @@ -0,0 +1,49 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/hid/irs.h" + +namespace Service::HID { + +IRS::IRS() : ServiceFramework{"irs"} { + // clang-format off + static const FunctionInfo functions[] = { + {302, nullptr, "ActivateIrsensor"}, + {303, nullptr, "DeactivateIrsensor"}, + {304, nullptr, "GetIrsensorSharedMemoryHandle"}, + {305, nullptr, "StopImageProcessor"}, + {306, nullptr, "RunMomentProcessor"}, + {307, nullptr, "RunClusteringProcessor"}, + {308, nullptr, "RunImageTransferProcessor"}, + {309, nullptr, "GetImageTransferProcessorState"}, + {310, nullptr, "RunTeraPluginProcessor"}, + {311, nullptr, "GetNpadIrCameraHandle"}, + {312, nullptr, "RunPointingProcessor"}, + {313, nullptr, "SuspendImageProcessor"}, + {314, nullptr, "CheckFirmwareVersion"}, + {315, nullptr, "SetFunctionLevel"}, + {316, nullptr, "RunImageTransferExProcessor"}, + {317, nullptr, "RunIrLedProcessor"}, + {318, nullptr, "StopImageProcessorAsync"}, + {319, nullptr, "ActivateIrsensorWithFunctionLevel"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {500, nullptr, "SetAppletResourceUserId"}, + {501, nullptr, "RegisterAppletResourceUserId"}, + {502, nullptr, "UnregisterAppletResourceUserId"}, + {503, nullptr, "EnableAppletToGetInput"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h new file mode 100644 index 000000000..a8be701c7 --- /dev/null +++ b/src/core/hle/service/hid/irs.h @@ -0,0 +1,21 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::HID { + +class IRS final : public ServiceFramework<IRS> { +public: + explicit IRS(); +}; + +class IRS_SYS final : public ServiceFramework<IRS_SYS> { +public: + explicit IRS_SYS(); +}; + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp new file mode 100644 index 000000000..49f733f60 --- /dev/null +++ b/src/core/hle/service/hid/xcd.cpp @@ -0,0 +1,37 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/hid/xcd.h" + +namespace Service::HID { + +XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetDataFormat"}, + {1, nullptr, "SetDataFormat"}, + {2, nullptr, "GetMcuState"}, + {3, nullptr, "SetMcuState"}, + {4, nullptr, "GetMcuVersionForNfc"}, + {5, nullptr, "CheckNfcDevicePower"}, + {10, nullptr, "SetNfcEvent"}, + {11, nullptr, "GetNfcInfo"}, + {12, nullptr, "StartNfcDiscovery"}, + {13, nullptr, "StopNfcDiscovery"}, + {14, nullptr, "StartNtagRead"}, + {15, nullptr, "StartNtagWrite"}, + {16, nullptr, "SendNfcRawData"}, + {17, nullptr, "RegisterMifareKey"}, + {18, nullptr, "ClearMifareKey"}, + {19, nullptr, "StartMifareRead"}, + {20, nullptr, "StartMifareWrite"}, + {101, nullptr, "GetAwakeTriggerReasonForLeftRail"}, + {102, nullptr, "GetAwakeTriggerReasonForRightRail"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h new file mode 100644 index 000000000..232a044df --- /dev/null +++ b/src/core/hle/service/hid/xcd.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::HID { + +class XCD_SYS final : public ServiceFramework<XCD_SYS> { +public: + explicit XCD_SYS(); +}; + +} // namespace Service::HID diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp new file mode 100644 index 000000000..8fc8b1057 --- /dev/null +++ b/src/core/hle/service/lbl/lbl.cpp @@ -0,0 +1,90 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/lbl/lbl.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::LBL { + +class LBL final : public ServiceFramework<LBL> { +public: + explicit LBL() : ServiceFramework{"lbl"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + {6, nullptr, "TurnOffBacklight"}, + {7, nullptr, "TurnOnBacklight"}, + {8, nullptr, "GetBacklightStatus"}, + {9, nullptr, "Unknown7"}, + {10, nullptr, "Unknown8"}, + {11, nullptr, "Unknown9"}, + {12, nullptr, "Unknown10"}, + {13, nullptr, "Unknown11"}, + {14, nullptr, "Unknown12"}, + {15, nullptr, "Unknown13"}, + {16, nullptr, "ReadRawLightSensor"}, + {17, nullptr, "Unknown14"}, + {18, nullptr, "Unknown15"}, + {19, nullptr, "Unknown16"}, + {20, nullptr, "Unknown17"}, + {21, nullptr, "Unknown18"}, + {22, nullptr, "Unknown19"}, + {23, nullptr, "Unknown20"}, + {24, nullptr, "Unknown21"}, + {25, nullptr, "Unknown22"}, + {26, &LBL::EnableVrMode, "EnableVrMode"}, + {27, &LBL::DisableVrMode, "DisableVrMode"}, + {28, &LBL::GetVrMode, "GetVrMode"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void EnableVrMode(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + vr_mode_enabled = true; + + LOG_DEBUG(Service_LBL, "called"); + } + + void DisableVrMode(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + vr_mode_enabled = false; + + LOG_DEBUG(Service_LBL, "called"); + } + + void GetVrMode(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(vr_mode_enabled); + + LOG_DEBUG(Service_LBL, "called"); + } + + bool vr_mode_enabled = false; +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<LBL>()->InstallAsService(sm); +} + +} // namespace Service::LBL diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h new file mode 100644 index 000000000..bf6f400f8 --- /dev/null +++ b/src/core/hle/service/lbl/lbl.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::LBL { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::LBL diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp new file mode 100644 index 000000000..167f2c66a --- /dev/null +++ b/src/core/hle/service/ldn/ldn.cpp @@ -0,0 +1,142 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/ipc_helpers.h" +#include "core/hle/result.h" +#include "core/hle/service/ldn/ldn.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::LDN { + +class IMonitorService final : public ServiceFramework<IMonitorService> { +public: + explicit IMonitorService() : ServiceFramework{"IMonitorService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetStateForMonitor"}, + {1, nullptr, "GetNetworkInfoForMonitor"}, + {2, nullptr, "GetIpv4AddressForMonitor"}, + {3, nullptr, "GetDisconnectReasonForMonitor"}, + {4, nullptr, "GetSecurityParameterForMonitor"}, + {5, nullptr, "GetNetworkConfigForMonitor"}, + {100, nullptr, "InitializeMonitor"}, + {101, nullptr, "FinalizeMonitor"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class LDNM final : public ServiceFramework<LDNM> { +public: + explicit LDNM() : ServiceFramework{"ldn:m"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &LDNM::CreateMonitorService, "CreateMonitorService"} + }; + // clang-format on + + RegisterHandlers(functions); + } + + void CreateMonitorService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IMonitorService>(); + + LOG_DEBUG(Service_LDN, "called"); + } +}; + +class ILocalCommunicationService final : public ServiceFramework<ILocalCommunicationService> { +public: + explicit ILocalCommunicationService(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetState"}, + {1, nullptr, "GetNetworkInfo"}, + {2, nullptr, "GetIpv4Address"}, + {3, nullptr, "GetDisconnectReason"}, + {4, nullptr, "GetSecurityParameter"}, + {5, nullptr, "GetNetworkConfig"}, + {100, nullptr, "AttachStateChangeEvent"}, + {101, nullptr, "GetNetworkInfoLatestUpdate"}, + {102, nullptr, "Scan"}, + {103, nullptr, "ScanPrivate"}, + {200, nullptr, "OpenAccessPoint"}, + {201, nullptr, "CloseAccessPoint"}, + {202, nullptr, "CreateNetwork"}, + {203, nullptr, "CreateNetworkPrivate"}, + {204, nullptr, "DestroyNetwork"}, + {205, nullptr, "Reject"}, + {206, nullptr, "SetAdvertiseData"}, + {207, nullptr, "SetStationAcceptPolicy"}, + {208, nullptr, "AddAcceptFilterEntry"}, + {209, nullptr, "ClearAcceptFilter"}, + {300, nullptr, "OpenStation"}, + {301, nullptr, "CloseStation"}, + {302, nullptr, "Connect"}, + {303, nullptr, "ConnectPrivate"}, + {304, nullptr, "Disconnect"}, + {400, nullptr, "InitializeSystem"}, + {401, nullptr, "FinalizeSystem"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class LDNS final : public ServiceFramework<LDNS> { +public: + explicit LDNS() : ServiceFramework{"ldn:s"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + + void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); + + LOG_DEBUG(Service_LDN, "called"); + } +}; + +class LDNU final : public ServiceFramework<LDNU> { +public: + explicit LDNU() : ServiceFramework{"ldn:u"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + + void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); + + LOG_DEBUG(Service_LDN, "called"); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<LDNM>()->InstallAsService(sm); + std::make_shared<LDNS>()->InstallAsService(sm); + std::make_shared<LDNU>()->InstallAsService(sm); +} + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h new file mode 100644 index 000000000..6b2a3c2b2 --- /dev/null +++ b/src/core/hle/service/ldn/ldn.h @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::LDN { + +/// Registers all LDN services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::LDN diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp new file mode 100644 index 000000000..a6197124a --- /dev/null +++ b/src/core/hle/service/mii/mii.cpp @@ -0,0 +1,107 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/mii/mii.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Mii { + +class IDatabaseService final : public ServiceFramework<IDatabaseService> { +public: + explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "IsUpdated"}, + {1, nullptr, "IsFullDatabase"}, + {2, nullptr, "GetCount"}, + {3, nullptr, "Get"}, + {4, nullptr, "Get1"}, + {5, nullptr, "UpdateLatest"}, + {6, nullptr, "BuildRandom"}, + {7, nullptr, "BuildDefault"}, + {8, nullptr, "Get2"}, + {9, nullptr, "Get3"}, + {10, nullptr, "UpdateLatest1"}, + {11, nullptr, "FindIndex"}, + {12, nullptr, "Move"}, + {13, nullptr, "AddOrReplace"}, + {14, nullptr, "Delete"}, + {15, nullptr, "DestroyFile"}, + {16, nullptr, "DeleteFile"}, + {17, nullptr, "Format"}, + {18, nullptr, "Import"}, + {19, nullptr, "Export"}, + {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, + {21, nullptr, "GetIndex"}, + {22, nullptr, "SetInterfaceVersion"}, + {23, nullptr, "Convert"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class MiiDBModule final : public ServiceFramework<MiiDBModule> { +public: + explicit MiiDBModule(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void GetDatabaseService(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IDatabaseService>(); + + LOG_DEBUG(Service_Mii, "called"); + } +}; + +class MiiImg final : public ServiceFramework<MiiImg> { +public: + explicit MiiImg() : ServiceFramework{"miiimg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {10, nullptr, "Reload"}, + {11, nullptr, "GetCount"}, + {12, nullptr, "IsEmpty"}, + {13, nullptr, "IsFull"}, + {14, nullptr, "GetAttribute"}, + {15, nullptr, "LoadImage"}, + {16, nullptr, "AddOrUpdateImage"}, + {17, nullptr, "DeleteImages"}, + {100, nullptr, "DeleteFile"}, + {101, nullptr, "DestroyFile"}, + {102, nullptr, "ImportFile"}, + {103, nullptr, "ExportFile"}, + {104, nullptr, "ForceInitialize"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<MiiDBModule>("mii:e")->InstallAsService(sm); + std::make_shared<MiiDBModule>("mii:u")->InstallAsService(sm); + + std::make_shared<MiiImg>()->InstallAsService(sm); +} + +} // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h new file mode 100644 index 000000000..7ce9be50e --- /dev/null +++ b/src/core/hle/service/mii/mii.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::Mii { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::Mii diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp new file mode 100644 index 000000000..0297edca0 --- /dev/null +++ b/src/core/hle/service/ncm/ncm.cpp @@ -0,0 +1,59 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/ncm/ncm.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::NCM { + +class LocationResolver final : public ServiceFramework<LocationResolver> { +public: + explicit LocationResolver() : ServiceFramework{"lr"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "OpenLocationResolver"}, + {1, nullptr, "OpenRegisteredLocationResolver"}, + {2, nullptr, "RefreshLocationResolver"}, + {3, nullptr, "OpenAddOnContentLocationResolver"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NCM final : public ServiceFramework<NCM> { +public: + explicit NCM() : ServiceFramework{"ncm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateContentStorage"}, + {1, nullptr, "CreateContentMetaDatabase"}, + {2, nullptr, "VerifyContentStorage"}, + {3, nullptr, "VerifyContentMetaDatabase"}, + {4, nullptr, "OpenContentStorage"}, + {5, nullptr, "OpenContentMetaDatabase"}, + {6, nullptr, "CloseContentStorageForcibly"}, + {7, nullptr, "CloseContentMetaDatabaseForcibly"}, + {8, nullptr, "CleanupContentMetaDatabase"}, + {9, nullptr, "OpenContentStorage2"}, + {10, nullptr, "CloseContentStorage"}, + {11, nullptr, "OpenContentMetaDatabase2"}, + {12, nullptr, "CloseContentMetaDatabase"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<LocationResolver>()->InstallAsService(sm); + std::make_shared<NCM>()->InstallAsService(sm); +} + +} // namespace Service::NCM diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h new file mode 100644 index 000000000..7bc8518a6 --- /dev/null +++ b/src/core/hle/service/ncm/ncm.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::NCM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::NCM diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp new file mode 100644 index 000000000..8fec97db8 --- /dev/null +++ b/src/core/hle/service/nfc/nfc.cpp @@ -0,0 +1,222 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/nfc/nfc.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::NFC { + +class IAm final : public ServiceFramework<IAm> { +public: + explicit IAm() : ServiceFramework{"IAm"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Finalize"}, + {2, nullptr, "NotifyForegroundApplet"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NFC_AM final : public ServiceFramework<NFC_AM> { +public: + explicit NFC_AM() : ServiceFramework{"nfc:am"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateAmInterface(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IAm>(); + + LOG_DEBUG(Service_NFC, "called"); + } +}; + +class MFIUser final : public ServiceFramework<MFIUser> { +public: + explicit MFIUser() : ServiceFramework{"IUser"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Finalize"}, + {2, nullptr, "ListDevices"}, + {3, nullptr, "StartDetection"}, + {4, nullptr, "StopDetection"}, + {5, nullptr, "Read"}, + {6, nullptr, "Write"}, + {7, nullptr, "GetTagInfo"}, + {8, nullptr, "GetActivateEventHandle"}, + {9, nullptr, "GetDeactivateEventHandle"}, + {10, nullptr, "GetState"}, + {11, nullptr, "GetDeviceState"}, + {12, nullptr, "GetNpadId"}, + {13, nullptr, "GetAvailabilityChangeEventHandle"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { +public: + explicit NFC_MF_U() : ServiceFramework{"nfc:mf:u"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateUserInterface(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<MFIUser>(); + + LOG_DEBUG(Service_NFC, "called"); + } +}; + +class IUser final : public ServiceFramework<IUser> { +public: + explicit IUser() : ServiceFramework{"IUser"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Finalize"}, + {2, nullptr, "GetState"}, + {3, nullptr, "IsNfcEnabled"}, + {400, nullptr, "Initialize"}, + {401, nullptr, "Finalize"}, + {402, nullptr, "GetState"}, + {403, nullptr, "IsNfcEnabled"}, + {404, nullptr, "ListDevices"}, + {405, nullptr, "GetDeviceState"}, + {406, nullptr, "GetNpadId"}, + {407, nullptr, "AttachAvailabilityChangeEvent"}, + {408, nullptr, "StartDetection"}, + {409, nullptr, "StopDetection"}, + {410, nullptr, "GetTagInfo"}, + {411, nullptr, "AttachActivateEvent"}, + {412, nullptr, "AttachDeactivateEvent"}, + {1000, nullptr, "ReadMifare"}, + {1001, nullptr, "WriteMifare"}, + {1300, nullptr, "SendCommandByPassThrough"}, + {1301, nullptr, "KeepPassThroughSession"}, + {1302, nullptr, "ReleasePassThroughSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NFC_U final : public ServiceFramework<NFC_U> { +public: + explicit NFC_U() : ServiceFramework{"nfc:u"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateUserInterface(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IUser>(); + + LOG_DEBUG(Service_NFC, "called"); + } +}; + +class ISystem final : public ServiceFramework<ISystem> { +public: + explicit ISystem() : ServiceFramework{"ISystem"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Finalize"}, + {2, nullptr, "GetState"}, + {3, nullptr, "IsNfcEnabled"}, + {100, nullptr, "SetNfcEnabled"}, + {400, nullptr, "InitializeSystem"}, + {401, nullptr, "FinalizeSystem"}, + {402, nullptr, "GetState"}, + {403, nullptr, "IsNfcEnabled"}, + {404, nullptr, "ListDevices"}, + {405, nullptr, "GetDeviceState"}, + {406, nullptr, "GetNpadId"}, + {407, nullptr, "AttachAvailabilityChangeEvent"}, + {408, nullptr, "StartDetection"}, + {409, nullptr, "StopDetection"}, + {410, nullptr, "GetTagInfo"}, + {411, nullptr, "AttachActivateEvent"}, + {412, nullptr, "AttachDeactivateEvent"}, + {500, nullptr, "SetNfcEnabled"}, + {1000, nullptr, "ReadMifare"}, + {1001, nullptr, "WriteMifare"}, + {1300, nullptr, "SendCommandByPassThrough"}, + {1301, nullptr, "KeepPassThroughSession"}, + {1302, nullptr, "ReleasePassThroughSession"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NFC_SYS final : public ServiceFramework<NFC_SYS> { +public: + explicit NFC_SYS() : ServiceFramework{"nfc:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateSystemInterface(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISystem>(); + + LOG_DEBUG(Service_NFC, "called"); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<NFC_AM>()->InstallAsService(sm); + std::make_shared<NFC_MF_U>()->InstallAsService(sm); + std::make_shared<NFC_U>()->InstallAsService(sm); + std::make_shared<NFC_SYS>()->InstallAsService(sm); +} + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h new file mode 100644 index 000000000..4d2d815f9 --- /dev/null +++ b/src/core/hle/service/nfc/nfc.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::NFC { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::NFC diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp new file mode 100644 index 000000000..bd05b0a70 --- /dev/null +++ b/src/core/hle/service/nim/nim.cpp @@ -0,0 +1,124 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::NIM { + +class NIM final : public ServiceFramework<NIM> { +public: + explicit NIM() : ServiceFramework{"nim"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CreateSystemUpdateTask"}, + {1, nullptr, "DestroySystemUpdateTask"}, + {2, nullptr, "ListSystemUpdateTask"}, + {3, nullptr, "RequestSystemUpdateTaskRun"}, + {4, nullptr, "GetSystemUpdateTaskInfo"}, + {5, nullptr, "CommitSystemUpdateTask"}, + {6, nullptr, "CreateNetworkInstallTask"}, + {7, nullptr, "DestroyNetworkInstallTask"}, + {8, nullptr, "ListNetworkInstallTask"}, + {9, nullptr, "RequestNetworkInstallTaskRun"}, + {10, nullptr, "GetNetworkInstallTaskInfo"}, + {11, nullptr, "CommitNetworkInstallTask"}, + {12, nullptr, "RequestLatestSystemUpdateMeta"}, + {14, nullptr, "ListApplicationNetworkInstallTask"}, + {15, nullptr, "ListNetworkInstallTaskContentMeta"}, + {16, nullptr, "RequestLatestVersion"}, + {17, nullptr, "SetNetworkInstallTaskAttribute"}, + {18, nullptr, "AddNetworkInstallTaskContentMeta"}, + {19, nullptr, "GetDownloadedSystemDataPath"}, + {20, nullptr, "CalculateNetworkInstallTaskRequiredSize"}, + {21, nullptr, "IsExFatDriverIncluded"}, + {22, nullptr, "GetBackgroundDownloadStressTaskInfo"}, + {23, nullptr, "RequestDeviceAuthenticationToken"}, + {24, nullptr, "RequestGameCardRegistrationStatus"}, + {25, nullptr, "RequestRegisterGameCard"}, + {26, nullptr, "RequestRegisterNotificationToken"}, + {27, nullptr, "RequestDownloadTaskList"}, + {28, nullptr, "RequestApplicationControl"}, + {29, nullptr, "RequestLatestApplicationControl"}, + {30, nullptr, "RequestVersionList"}, + {31, nullptr, "CreateApplyDeltaTask"}, + {32, nullptr, "DestroyApplyDeltaTask"}, + {33, nullptr, "ListApplicationApplyDeltaTask"}, + {34, nullptr, "RequestApplyDeltaTaskRun"}, + {35, nullptr, "GetApplyDeltaTaskInfo"}, + {36, nullptr, "ListApplyDeltaTask"}, + {37, nullptr, "CommitApplyDeltaTask"}, + {38, nullptr, "CalculateApplyDeltaTaskRequiredSize"}, + {39, nullptr, "PrepareShutdown"}, + {40, nullptr, "ListApplyDeltaTask"}, + {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, + {42, nullptr, "Unknown1"}, + {43, nullptr, "Unknown2"}, + {44, nullptr, "Unknown3"}, + {45, nullptr, "Unknown4"}, + {46, nullptr, "Unknown5"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NIM_SHP final : public ServiceFramework<NIM_SHP> { +public: + explicit NIM_SHP() : ServiceFramework{"nim:shp"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RequestDeviceAuthenticationToken"}, + {1, nullptr, "RequestCachedDeviceAuthenticationToken"}, + {100, nullptr, "RequestRegisterDeviceAccount"}, + {101, nullptr, "RequestUnregisterDeviceAccount"}, + {102, nullptr, "RequestDeviceAccountStatus"}, + {103, nullptr, "GetDeviceAccountInfo"}, + {104, nullptr, "RequestDeviceRegistrationInfo"}, + {105, nullptr, "RequestTransferDeviceAccount"}, + {106, nullptr, "RequestSyncRegistration"}, + {107, nullptr, "IsOwnDeviceId"}, + {200, nullptr, "RequestRegisterNotificationToken"}, + {300, nullptr, "RequestUnlinkDevice"}, + {301, nullptr, "RequestUnlinkDeviceIntegrated"}, + {302, nullptr, "RequestLinkDevice"}, + {303, nullptr, "HasDeviceLink"}, + {304, nullptr, "RequestUnlinkDeviceAll"}, + {305, nullptr, "RequestCreateVirtualAccount"}, + {306, nullptr, "RequestDeviceLinkStatus"}, + {400, nullptr, "GetAccountByVirtualAccount"}, + {500, nullptr, "RequestSyncTicket"}, + {501, nullptr, "RequestDownloadTicket"}, + {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class NTC final : public ServiceFramework<NTC> { +public: + explicit NTC() : ServiceFramework{"ntc"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "OpenEnsureNetworkClockAvailabilityService"}, + {100, nullptr, "SuspendAutonomicTimeCorrection"}, + {101, nullptr, "ResumeAutonomicTimeCorrection"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<NIM>()->InstallAsService(sm); + std::make_shared<NIM_SHP>()->InstallAsService(sm); + std::make_shared<NTC>()->InstallAsService(sm); +} + +} // namespace Service::NIM diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h new file mode 100644 index 000000000..2a2a92df0 --- /dev/null +++ b/src/core/hle/service/nim/nim.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::NIM { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::NIM diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp new file mode 100644 index 000000000..39cf05eba --- /dev/null +++ b/src/core/hle/service/pcie/pcie.cpp @@ -0,0 +1,64 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/pcie/pcie.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::PCIe { + +class ISession final : public ServiceFramework<ISession> { +public: + explicit ISession() : ServiceFramework{"ISession"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "QueryFunctions"}, + {1, nullptr, "AcquireFunction"}, + {2, nullptr, "ReleaseFunction"}, + {3, nullptr, "GetFunctionState"}, + {4, nullptr, "GetBarProfile"}, + {5, nullptr, "ReadConfig"}, + {6, nullptr, "WriteConfig"}, + {7, nullptr, "ReadBarRegion"}, + {8, nullptr, "WriteBarRegion"}, + {9, nullptr, "FindCapability"}, + {10, nullptr, "FindExtendedCapability"}, + {11, nullptr, "MapDma"}, + {12, nullptr, "UnmapDma"}, + {13, nullptr, "UnmapDmaBusAddress"}, + {14, nullptr, "GetDmaBusAddress"}, + {15, nullptr, "GetDmaBusAddressRange"}, + {16, nullptr, "SetDmaEnable"}, + {17, nullptr, "AcquireIrq"}, + {18, nullptr, "ReleaseIrq"}, + {19, nullptr, "SetIrqEnable"}, + {20, nullptr, "SetAspmEnable"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class PCIe final : public ServiceFramework<PCIe> { +public: + explicit PCIe() : ServiceFramework{"pcie"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RegisterClassDriver"}, + {1, nullptr, "QueryFunctionsUnregistered"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<PCIe>()->InstallAsService(sm); +} + +} // namespace Service::PCIe diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h new file mode 100644 index 000000000..59c22ca45 --- /dev/null +++ b/src/core/hle/service/pcie/pcie.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::PCIe { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::PCIe diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 482989ea7..fccc4c461 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -21,20 +21,31 @@ #include "core/hle/service/apm/apm.h" #include "core/hle/service/audio/audio.h" #include "core/hle/service/bcat/bcat.h" +#include "core/hle/service/btdrv/btdrv.h" +#include "core/hle/service/btm/btm.h" #include "core/hle/service/erpt/erpt.h" #include "core/hle/service/es/es.h" #include "core/hle/service/eupld/eupld.h" #include "core/hle/service/fatal/fatal.h" +#include "core/hle/service/fgm/fgm.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/friend/friend.h" +#include "core/hle/service/grc/grc.h" #include "core/hle/service/hid/hid.h" +#include "core/hle/service/lbl/lbl.h" +#include "core/hle/service/ldn/ldn.h" #include "core/hle/service/ldr/ldr.h" #include "core/hle/service/lm/lm.h" +#include "core/hle/service/mii/mii.h" #include "core/hle/service/mm/mm_u.h" +#include "core/hle/service/ncm/ncm.h" +#include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nifm/nifm.h" +#include "core/hle/service/nim/nim.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/pcie/pcie.h" #include "core/hle/service/pctl/pctl.h" #include "core/hle/service/pm/pm.h" #include "core/hle/service/prepo/prepo.h" @@ -47,6 +58,7 @@ #include "core/hle/service/ssl/ssl.h" #include "core/hle/service/time/time.h" #include "core/hle/service/vi/vi.h" +#include "core/hle/service/wlan/wlan.h" using Kernel::ClientPort; using Kernel::ServerPort; @@ -190,31 +202,43 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { AM::InstallInterfaces(*sm, nv_flinger); AOC::InstallInterfaces(*sm); APM::InstallInterfaces(*sm); - BCAT::InstallInterfaces(*sm); Audio::InstallInterfaces(*sm); + BCAT::InstallInterfaces(*sm); + BtDrv::InstallInterfaces(*sm); + BTM::InstallInterfaces(*sm); ERPT::InstallInterfaces(*sm); ES::InstallInterfaces(*sm); EUPLD::InstallInterfaces(*sm); Fatal::InstallInterfaces(*sm); + FGM::InstallInterfaces(*sm); FileSystem::InstallInterfaces(*sm); Friend::InstallInterfaces(*sm); + GRC::InstallInterfaces(*sm); HID::InstallInterfaces(*sm); + LBL::InstallInterfaces(*sm); + LDN::InstallInterfaces(*sm); LDR::InstallInterfaces(*sm); LM::InstallInterfaces(*sm); + Mii::InstallInterfaces(*sm); MM::InstallInterfaces(*sm); + NCM::InstallInterfaces(*sm); + NFC::InstallInterfaces(*sm); NFP::InstallInterfaces(*sm); NIFM::InstallInterfaces(*sm); + NIM::InstallInterfaces(*sm); NS::InstallInterfaces(*sm); Nvidia::InstallInterfaces(*sm); + PCIe::InstallInterfaces(*sm); PCTL::InstallInterfaces(*sm); PlayReport::InstallInterfaces(*sm); PM::InstallInterfaces(*sm); + Set::InstallInterfaces(*sm); Sockets::InstallInterfaces(*sm); SPL::InstallInterfaces(*sm); SSL::InstallInterfaces(*sm); Time::InstallInterfaces(*sm); VI::InstallInterfaces(*sm, nv_flinger); - Set::InstallInterfaces(*sm); + WLAN::InstallInterfaces(*sm); LOG_DEBUG(Service, "initialized OK"); } diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 6aa1e2511..3211a8346 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -109,4 +109,26 @@ BSD::BSD(const char* name) : ServiceFramework(name) { RegisterHandlers(functions); } +BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "SetIfUp"}, + {1, nullptr, "SetIfUpWithEvent"}, + {2, nullptr, "CancelIf"}, + {3, nullptr, "SetIfDown"}, + {4, nullptr, "GetIfState"}, + {5, nullptr, "DhcpRenew"}, + {6, nullptr, "AddStaticArpEntry"}, + {7, nullptr, "RemoveArpEntry"}, + {8, nullptr, "LookupArpEntry"}, + {9, nullptr, "LookupArpEntry2"}, + {10, nullptr, "ClearArpEntries"}, + {11, nullptr, "ClearArpEntries2"}, + {12, nullptr, "PrintArpEntries"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index a6b1ca7d0..c1da59b24 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -26,4 +26,9 @@ private: u32 next_fd = 1; }; +class BSDCFG final : public ServiceFramework<BSDCFG> { +public: + explicit BSDCFG(); +}; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp new file mode 100644 index 000000000..d53c25eec --- /dev/null +++ b/src/core/hle/service/sockets/ethc.cpp @@ -0,0 +1,38 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/sockets/ethc.h" + +namespace Service::Sockets { + +ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Initialize"}, + {1, nullptr, "Cancel"}, + {2, nullptr, "GetResult"}, + {3, nullptr, "GetMediaList"}, + {4, nullptr, "SetMediaType"}, + {5, nullptr, "GetMediaType"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetReadableHandle"}, + {1, nullptr, "Cancel"}, + {2, nullptr, "GetResult"}, + {3, nullptr, "GetInterfaceList"}, + {4, nullptr, "GetInterfaceCount"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h new file mode 100644 index 000000000..9a3c88100 --- /dev/null +++ b/src/core/hle/service/sockets/ethc.h @@ -0,0 +1,21 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service::Sockets { + +class ETHC_C final : public ServiceFramework<ETHC_C> { +public: + explicit ETHC_C(); +}; + +class ETHC_I final : public ServiceFramework<ETHC_I> { +public: + explicit ETHC_I(); +}; + +} // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp index 05bd10d35..08d2d306a 100644 --- a/src/core/hle/service/sockets/sockets.cpp +++ b/src/core/hle/service/sockets/sockets.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/service/sockets/bsd.h" +#include "core/hle/service/sockets/ethc.h" #include "core/hle/service/sockets/nsd.h" #include "core/hle/service/sockets/sfdnsres.h" #include "core/hle/service/sockets/sockets.h" @@ -12,8 +13,14 @@ namespace Service::Sockets { void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager); std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager); + std::make_shared<BSDCFG>()->InstallAsService(service_manager); + + std::make_shared<ETHC_C>()->InstallAsService(service_manager); + std::make_shared<ETHC_I>()->InstallAsService(service_manager); + std::make_shared<NSD>("nsd:a")->InstallAsService(service_manager); std::make_shared<NSD>("nsd:u")->InstallAsService(service_manager); + std::make_shared<SFDNSRES>()->InstallAsService(service_manager); } diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp new file mode 100644 index 000000000..2654594c1 --- /dev/null +++ b/src/core/hle/service/wlan/wlan.cpp @@ -0,0 +1,172 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/wlan/wlan.h" + +namespace Service::WLAN { + +class WLANInfra final : public ServiceFramework<WLANInfra> { +public: + explicit WLANInfra() : ServiceFramework{"wlan:inf"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "GetMacAddress"}, + {3, nullptr, "StartScan"}, + {4, nullptr, "StopScan"}, + {5, nullptr, "Connect"}, + {6, nullptr, "CancelConnect"}, + {7, nullptr, "Disconnect"}, + {8, nullptr, "Unknown3"}, + {9, nullptr, "Unknown4"}, + {10, nullptr, "GetState"}, + {11, nullptr, "GetScanResult"}, + {12, nullptr, "GetRssi"}, + {13, nullptr, "ChangeRxAntenna"}, + {14, nullptr, "Unknown5"}, + {15, nullptr, "Unknown6"}, + {16, nullptr, "RequestWakeUp"}, + {17, nullptr, "RequestIfUpDown"}, + {18, nullptr, "Unknown7"}, + {19, nullptr, "Unknown8"}, + {20, nullptr, "Unknown9"}, + {21, nullptr, "Unknown10"}, + {22, nullptr, "Unknown11"}, + {23, nullptr, "Unknown12"}, + {24, nullptr, "Unknown13"}, + {25, nullptr, "Unknown14"}, + {26, nullptr, "Unknown15"}, + {27, nullptr, "Unknown16"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANLocal final : public ServiceFramework<WLANLocal> { +public: + explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + {6, nullptr, "GetMacAddress"}, + {7, nullptr, "CreateBss"}, + {8, nullptr, "DestroyBss"}, + {9, nullptr, "StartScan"}, + {10, nullptr, "StopScan"}, + {11, nullptr, "Connect"}, + {12, nullptr, "CancelConnect"}, + {13, nullptr, "Join"}, + {14, nullptr, "CancelJoin"}, + {15, nullptr, "Disconnect"}, + {16, nullptr, "SetBeaconLostCount"}, + {17, nullptr, "Unknown7"}, + {18, nullptr, "Unknown8"}, + {19, nullptr, "Unknown9"}, + {20, nullptr, "GetBssIndicationEvent"}, + {21, nullptr, "GetBssIndicationInfo"}, + {22, nullptr, "GetState"}, + {23, nullptr, "GetAllowedChannels"}, + {24, nullptr, "AddIe"}, + {25, nullptr, "DeleteIe"}, + {26, nullptr, "Unknown10"}, + {27, nullptr, "Unknown11"}, + {28, nullptr, "CreateRxEntry"}, + {29, nullptr, "DeleteRxEntry"}, + {30, nullptr, "Unknown12"}, + {31, nullptr, "Unknown13"}, + {32, nullptr, "AddMatchingDataToRxEntry"}, + {33, nullptr, "RemoveMatchingDataFromRxEntry"}, + {34, nullptr, "GetScanResult"}, + {35, nullptr, "Unknown14"}, + {36, nullptr, "SetActionFrameWithBeacon"}, + {37, nullptr, "CancelActionFrameWithBeacon"}, + {38, nullptr, "CreateRxEntryForActionFrame"}, + {39, nullptr, "DeleteRxEntryForActionFrame"}, + {40, nullptr, "Unknown15"}, + {41, nullptr, "Unknown16"}, + {42, nullptr, "CancelGetActionFrame"}, + {43, nullptr, "GetRssi"}, + {44, nullptr, "Unknown17"}, + {45, nullptr, "Unknown18"}, + {46, nullptr, "Unknown19"}, + {47, nullptr, "Unknown20"}, + {48, nullptr, "Unknown21"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { +public: + explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { +public: + explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { +public: + explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "Unknown1"}, + {1, nullptr, "Unknown2"}, + {2, nullptr, "Unknown3"}, + {3, nullptr, "Unknown4"}, + {4, nullptr, "Unknown5"}, + {5, nullptr, "Unknown6"}, + {6, nullptr, "GetMacAddress"}, + {7, nullptr, "SwitchTsfTimerFunction"}, + {8, nullptr, "Unknown7"}, + {9, nullptr, "Unknown8"}, + {10, nullptr, "Unknown9"}, + {11, nullptr, "Unknown10"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +void InstallInterfaces(SM::ServiceManager& sm) { + std::make_shared<WLANInfra>()->InstallAsService(sm); + std::make_shared<WLANLocal>()->InstallAsService(sm); + std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm); + std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm); + std::make_shared<WLANSocketManager>()->InstallAsService(sm); +} + +} // namespace Service::WLAN diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h new file mode 100644 index 000000000..054ea928a --- /dev/null +++ b/src/core/hle/service/wlan/wlan.h @@ -0,0 +1,15 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::WLAN { + +void InstallInterfaces(SM::ServiceManager& sm); + +} // namespace Service::WLAN diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index de276c559..c464fc6d1 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -29,6 +29,7 @@ enum class RenderTargetFormat : u32 { RG16_UINT = 0xDD, RG16_FLOAT = 0xDE, R11G11B10_FLOAT = 0xE0, + R16_FLOAT = 0xF2, R8_UNORM = 0xF3, }; diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 2f814a184..ca923d17d 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -13,8 +13,10 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { ASSERT(gpu_addr); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(*gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped)); - PageSlot(*gpu_addr + offset) = static_cast<u64>(PageStatus::Allocated); + VAddr& slot = PageSlot(*gpu_addr + offset); + + ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); + slot = static_cast<u64>(PageStatus::Allocated); } return *gpu_addr; @@ -22,8 +24,10 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) { for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped)); - PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Allocated); + VAddr& slot = PageSlot(gpu_addr + offset); + + ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); + slot = static_cast<u64>(PageStatus::Allocated); } return gpu_addr; @@ -34,8 +38,10 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { ASSERT(gpu_addr); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(*gpu_addr + offset) == static_cast<u64>(PageStatus::Unmapped)); - PageSlot(*gpu_addr + offset) = cpu_addr + offset; + VAddr& slot = PageSlot(*gpu_addr + offset); + + ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); + slot = cpu_addr + offset; } MappedRegion region{cpu_addr, *gpu_addr, size}; @@ -48,8 +54,10 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) ASSERT((gpu_addr & PAGE_MASK) == 0); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(gpu_addr + offset) == static_cast<u64>(PageStatus::Allocated)); - PageSlot(gpu_addr + offset) = cpu_addr + offset; + VAddr& slot = PageSlot(gpu_addr + offset); + + ASSERT(slot == static_cast<u64>(PageStatus::Allocated)); + slot = cpu_addr + offset; } MappedRegion region{cpu_addr, gpu_addr, size}; @@ -62,9 +70,11 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { ASSERT((gpu_addr & PAGE_MASK) == 0); for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { - ASSERT(PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Allocated) && - PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Unmapped)); - PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Unmapped); + VAddr& slot = PageSlot(gpu_addr + offset); + + ASSERT(slot != static_cast<u64>(PageStatus::Allocated) && + slot != static_cast<u64>(PageStatus::Unmapped)); + slot = static_cast<u64>(PageStatus::Unmapped); } // Delete the region mappings that are contained within the unmapped region @@ -128,9 +138,7 @@ VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) { auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; if (!block) { block = std::make_unique<PageBlock>(); - for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) { - (*block)[index] = static_cast<u64>(PageStatus::Unmapped); - } + block->fill(static_cast<VAddr>(PageStatus::Unmapped)); } return (*block)[(gpu_addr >> PAGE_BITS) & PAGE_BLOCK_MASK]; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index bb39c0a6f..bf0458b94 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -230,7 +230,8 @@ struct SurfaceParams { return PixelFormat::RG16; case Tegra::RenderTargetFormat::RG16_SNORM: return PixelFormat::RG16S; - + case Tegra::RenderTargetFormat::R16_FLOAT: + return PixelFormat::R16F; default: LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); UNREACHABLE(); @@ -437,6 +438,7 @@ struct SurfaceParams { case Tegra::RenderTargetFormat::RGBA32_FLOAT: case Tegra::RenderTargetFormat::RG32_FLOAT: case Tegra::RenderTargetFormat::RG16_FLOAT: + case Tegra::RenderTargetFormat::R16_FLOAT: return ComponentType::Float; case Tegra::RenderTargetFormat::RGBA32_UINT: case Tegra::RenderTargetFormat::RG16_UINT: diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp index d6647eeea..39ed3bccf 100644 --- a/src/yuzu/about_dialog.cpp +++ b/src/yuzu/about_dialog.cpp @@ -10,8 +10,9 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); ui->labelLogo->setPixmap(QIcon::fromTheme("yuzu").pixmap(200)); - ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( - Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + ui->labelBuildInfo->setText( + ui->labelBuildInfo->text().arg(Common::g_build_name, Common::g_scm_branch, + Common::g_scm_desc, QString(Common::g_build_date).left(10))); } AboutDialog::~AboutDialog() {} diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 2680480cc..f122ba39d 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui @@ -70,7 +70,7 @@ </sizepolicy> </property> <property name="text"> - <string><html><head/><body><p>%1 | %2-%3</p></body></html></string> + <string><html><head/><body><p>%1 | %2-%3 (%4)</p></body></html></string> </property> </widget> </item> @@ -115,7 +115,7 @@ p, li { white-space: pre-wrap; } <item> <widget class="QLabel" name="labelLinks"> <property name="text"> - <string><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#0000ff;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#0000ff;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#0000ff;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#0000ff;">License</span></a></p></body></html></string> + <string><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></string> </property> <property name="openExternalLinks"> <bool>true</bool> diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 5e66239ff..7fd07539a 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -44,5 +44,4 @@ void ConfigureDebug::applyConfiguration() { Log::Filter filter; filter.ParseFilterString(Settings::values.log_filter); Log::SetGlobalFilter(filter); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index baa558667..cb7d3f8bf 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -44,5 +44,4 @@ void ConfigureGeneral::applyConfiguration() { Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); Settings::values.use_multi_core = ui->use_multi_core->isChecked(); Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 7664880d5..3379b7963 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -67,5 +67,4 @@ void ConfigureGraphics::applyConfiguration() { ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked(); Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); - Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 78559e2bb..5e7badedf 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -191,8 +191,6 @@ void ConfigureInput::applyConfiguration() { [](const Common::ParamPackage& param) { return param.Serialize(); }); std::transform(analogs_param.begin(), analogs_param.end(), Settings::values.analogs.begin(), [](const Common::ParamPackage& param) { return param.Serialize(); }); - - Settings::Apply(); } void ConfigureInput::loadConfiguration() { diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 2b45b8573..f5a5697a0 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -328,11 +328,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { const auto& timer = static_cast<const Kernel::Timer&>(object); list.push_back(std::make_unique<WaitTreeText>( - tr("reset type = %1").arg(GetResetTypeQString(timer.reset_type)))); + tr("reset type = %1").arg(GetResetTypeQString(timer.GetResetType())))); list.push_back( - std::make_unique<WaitTreeText>(tr("initial delay = %1").arg(timer.initial_delay))); + std::make_unique<WaitTreeText>(tr("initial delay = %1").arg(timer.GetInitialDelay()))); list.push_back( - std::make_unique<WaitTreeText>(tr("interval delay = %1").arg(timer.interval_delay))); + std::make_unique<WaitTreeText>(tr("interval delay = %1").arg(timer.GetIntervalDelay()))); return list; } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3c2726498..be38cfa9b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -101,6 +101,8 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { ConnectMenuEvents(); ConnectWidgetEvents(); + LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_name, Common::g_scm_branch, + Common::g_scm_desc); setWindowTitle(QString("yuzu %1| %2-%3") .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); @@ -205,15 +207,27 @@ void GMainWindow::InitializeRecentFileMenuActions() { void GMainWindow::InitializeHotkeys() { RegisterHotkey("Main Window", "Load File", QKeySequence::Open); RegisterHotkey("Main Window", "Start Emulation"); + RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), Qt::ApplicationShortcut); + RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"), + Qt::ApplicationShortcut); LoadHotkeys(); connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); connect(GetHotkey("Main Window", "Start Emulation", this), &QShortcut::activated, this, &GMainWindow::OnStartGame); + connect(GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated, this, [&] { + if (emulation_running) { + if (emu_thread->IsRunning()) { + OnPauseGame(); + } else { + OnStartGame(); + } + } + }); connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activated, ui.action_Fullscreen, &QAction::trigger); connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activatedAmbiguously, @@ -224,6 +238,10 @@ void GMainWindow::InitializeHotkeys() { ToggleFullscreen(); } }); + connect(GetHotkey("Main Window", "Toggle Speed Limit", this), &QShortcut::activated, this, [&] { + Settings::values.toggle_framelimit = !Settings::values.toggle_framelimit; + UpdateStatusBar(); + }); } void GMainWindow::SetDefaultUIGeometry() { @@ -705,10 +723,12 @@ void GMainWindow::ToggleWindowMode() { void GMainWindow::OnConfigure() { ConfigureDialog configureDialog(this); + auto old_theme = UISettings::values.theme; auto result = configureDialog.exec(); if (result == QDialog::Accepted) { configureDialog.applyConfiguration(); - UpdateUITheme(); + if (UISettings::values.theme != old_theme) + UpdateUITheme(); config->Save(); } } @@ -939,7 +959,6 @@ int main(int argc, char* argv[]) { QCoreApplication::setOrganizationName("yuzu team"); QCoreApplication::setApplicationName("yuzu"); - QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); QApplication app(argc, argv); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 5eca38b48..567f23417 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -118,7 +118,7 @@ bg_green = layout_option = # Toggle custom layout (using the settings below) on or off. -# 0 (default): Off , 1: On +# 0 (default): Off, 1: On custom_layout = # Screen placement when using Custom layout option diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 72ba7d49c..e2945b6cf 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -164,6 +164,8 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { OnResize(); OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); SDL_PumpEvents(); + LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_name, Common::g_scm_branch, + Common::g_scm_desc); DoneCurrent(); } |