mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #823 from Subv/applets_drawing
Library applet support (swkbd for now)
This commit is contained in:
		
						commit
						f4e1d8ea36
					
				
					 11 changed files with 567 additions and 58 deletions
				
			
		|  | @ -25,6 +25,8 @@ set(SRCS | ||||||
|             file_sys/ivfc_archive.cpp |             file_sys/ivfc_archive.cpp | ||||||
|             hle/config_mem.cpp |             hle/config_mem.cpp | ||||||
|             hle/hle.cpp |             hle/hle.cpp | ||||||
|  |             hle/applets/applet.cpp | ||||||
|  |             hle/applets/swkbd.cpp | ||||||
|             hle/kernel/address_arbiter.cpp |             hle/kernel/address_arbiter.cpp | ||||||
|             hle/kernel/event.cpp |             hle/kernel/event.cpp | ||||||
|             hle/kernel/kernel.cpp |             hle/kernel/kernel.cpp | ||||||
|  | @ -150,6 +152,8 @@ set(HEADERS | ||||||
|             hle/config_mem.h |             hle/config_mem.h | ||||||
|             hle/function_wrappers.h |             hle/function_wrappers.h | ||||||
|             hle/hle.h |             hle/hle.h | ||||||
|  |             hle/applets/applet.h | ||||||
|  |             hle/applets/swkbd.h | ||||||
|             hle/kernel/address_arbiter.h |             hle/kernel/address_arbiter.h | ||||||
|             hle/kernel/event.h |             hle/kernel/event.h | ||||||
|             hle/kernel/kernel.h |             hle/kernel/kernel.h | ||||||
|  |  | ||||||
							
								
								
									
										94
									
								
								src/core/hle/applets/applet.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/core/hle/applets/applet.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | ||||||
|  | // Copyright 2015 Citra 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/hle/applets/applet.h" | ||||||
|  | #include "core/hle/applets/swkbd.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | // Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
 | ||||||
|  | // Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
 | ||||||
|  | namespace std { | ||||||
|  |     template <> | ||||||
|  |     struct hash<Service::APT::AppletId> { | ||||||
|  |         typedef Service::APT::AppletId argument_type; | ||||||
|  |         typedef std::size_t result_type; | ||||||
|  | 
 | ||||||
|  |         result_type operator()(const argument_type& id_code) const { | ||||||
|  |             typedef std::underlying_type<argument_type>::type Type; | ||||||
|  |             return std::hash<Type>()(static_cast<Type>(id_code)); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace HLE { | ||||||
|  | namespace Applets { | ||||||
|  | 
 | ||||||
|  | static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets; | ||||||
|  | static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
 | ||||||
|  | /// The interval at which the Applet update callback will be called, 16.6ms
 | ||||||
|  | static const u64 applet_update_interval_us = 16666; | ||||||
|  | 
 | ||||||
|  | ResultCode Applet::Create(Service::APT::AppletId id) { | ||||||
|  |     switch (id) { | ||||||
|  |     case Service::APT::AppletId::SoftwareKeyboard1: | ||||||
|  |     case Service::APT::AppletId::SoftwareKeyboard2: | ||||||
|  |         applets[id] = std::make_shared<SoftwareKeyboard>(id); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         // TODO(Subv): Find the right error code
 | ||||||
|  |         return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) { | ||||||
|  |     auto itr = applets.find(id); | ||||||
|  |     if (itr != applets.end()) | ||||||
|  |         return itr->second; | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Handles updating the current Applet every time it's called.
 | ||||||
|  | static void AppletUpdateEvent(u64 applet_id, int cycles_late) { | ||||||
|  |     Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); | ||||||
|  |     std::shared_ptr<Applet> applet = Applet::Get(id); | ||||||
|  |     ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); | ||||||
|  | 
 | ||||||
|  |     applet->Update(); | ||||||
|  | 
 | ||||||
|  |     // If the applet is still running after the last update, reschedule the event
 | ||||||
|  |     if (applet->IsRunning()) { | ||||||
|  |         CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, | ||||||
|  |             applet_update_event, applet_id); | ||||||
|  |     } else { | ||||||
|  |         // Otherwise the applet has terminated, in which case we should clean it up
 | ||||||
|  |         applets[id] = nullptr; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { | ||||||
|  |     ResultCode result = StartImpl(parameter); | ||||||
|  |     if (result.IsError()) | ||||||
|  |         return result; | ||||||
|  |     // Schedule the update event
 | ||||||
|  |     CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id)); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Init() { | ||||||
|  |     // Register the applet update callback
 | ||||||
|  |     applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Shutdown() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } // namespace
 | ||||||
							
								
								
									
										77
									
								
								src/core/hle/applets/applet.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/core/hle/applets/applet.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | ||||||
|  | // Copyright 2015 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/service/apt/apt.h" | ||||||
|  | 
 | ||||||
|  | namespace HLE { | ||||||
|  | namespace Applets { | ||||||
|  | 
 | ||||||
|  | class Applet { | ||||||
|  | public: | ||||||
|  |     virtual ~Applet() { } | ||||||
|  |     Applet(Service::APT::AppletId id) : id(id) { } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Creates an instance of the Applet subclass identified by the parameter. | ||||||
|  |      * and stores it in a global map. | ||||||
|  |      * @param id Id of the applet to create. | ||||||
|  |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|  |      */ | ||||||
|  |     static ResultCode Create(Service::APT::AppletId id); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Retrieves the Applet instance identified by the specified id. | ||||||
|  |      * @param id Id of the Applet to retrieve. | ||||||
|  |      * @returns Requested Applet or nullptr if not found. | ||||||
|  |      */ | ||||||
|  |     static std::shared_ptr<Applet> Get(Service::APT::AppletId id); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Handles a parameter from the application. | ||||||
|  |      * @param parameter Parameter data to handle. | ||||||
|  |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|  |      */ | ||||||
|  |     virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Handles the Applet start event, triggered from the application. | ||||||
|  |      * @param parameter Parameter data to handle. | ||||||
|  |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|  |      */ | ||||||
|  |     ResultCode Start(const Service::APT::AppletStartupParameter& parameter); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Whether the applet is currently executing instead of the host application or not. | ||||||
|  |      */ | ||||||
|  |     virtual bool IsRunning() const = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Handles an update tick for the Applet, lets it update the screen, send commands, etc. | ||||||
|  |      */ | ||||||
|  |     virtual void Update() = 0; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     /**
 | ||||||
|  |      * Handles the Applet start event, triggered from the application. | ||||||
|  |      * @param parameter Parameter data to handle. | ||||||
|  |      * @returns ResultCode Whether the operation was successful or not. | ||||||
|  |      */ | ||||||
|  |     virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; | ||||||
|  | 
 | ||||||
|  |     Service::APT::AppletId id; ///< Id of this Applet
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Initializes the HLE applets
 | ||||||
|  | void Init(); | ||||||
|  | 
 | ||||||
|  | /// Shuts down the HLE applets
 | ||||||
|  | void Shutdown(); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } // namespace
 | ||||||
							
								
								
									
										105
									
								
								src/core/hle/applets/swkbd.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/core/hle/applets/swkbd.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,105 @@ | ||||||
|  | // Copyright 2015 Citra 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 "common/string_util.h" | ||||||
|  | 
 | ||||||
|  | #include "core/hle/applets/swkbd.h" | ||||||
|  | #include "core/hle/service/hid/hid.h" | ||||||
|  | #include "core/hle/service/gsp_gpu.h" | ||||||
|  | #include "video_core/video_core.h" | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | namespace HLE { | ||||||
|  | namespace Applets { | ||||||
|  | 
 | ||||||
|  | SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) { | ||||||
|  |     // Create the SharedMemory that will hold the framebuffer data
 | ||||||
|  |     // TODO(Subv): What size should we use here?
 | ||||||
|  |     using Kernel::MemoryPermission; | ||||||
|  |     framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | ||||||
|  |     if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { | ||||||
|  |         LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||||||
|  |         UNIMPLEMENTED(); | ||||||
|  |         // TODO(Subv): Find the right error code
 | ||||||
|  |         return ResultCode(-1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Service::APT::MessageParameter result; | ||||||
|  |     // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
 | ||||||
|  |     result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); | ||||||
|  |     result.data = nullptr; | ||||||
|  |     result.buffer_size = 0; | ||||||
|  |     result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||||||
|  |     result.sender_id = static_cast<u32>(id); | ||||||
|  |     result.object = framebuffer_memory; | ||||||
|  | 
 | ||||||
|  |     Service::APT::SendParameter(result); | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { | ||||||
|  |     ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); | ||||||
|  | 
 | ||||||
|  |     memcpy(&config, parameter.data, parameter.buffer_size); | ||||||
|  |     text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Verify if this is the correct behavior
 | ||||||
|  |     memset(text_memory->GetPointer(), 0, text_memory->size); | ||||||
|  | 
 | ||||||
|  |     DrawScreenKeyboard(); | ||||||
|  | 
 | ||||||
|  |     started = true; | ||||||
|  |     return RESULT_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SoftwareKeyboard::Update() { | ||||||
|  |     // TODO(Subv): Handle input using the touch events from the HID module
 | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Remove this hardcoded text
 | ||||||
|  |     std::u16string text = Common::UTF8ToUTF16("Citra"); | ||||||
|  |     memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t)); | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Ask for input and write it to the shared memory
 | ||||||
|  |     // TODO(Subv): Find out what are the possible values for the return code,
 | ||||||
|  |     // some games seem to check for a hardcoded 2
 | ||||||
|  |     config.return_code = 2; | ||||||
|  |     config.text_length = 6; | ||||||
|  |     config.text_offset = 0; | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): We're finalizing the applet immediately after it's started,
 | ||||||
|  |     // but we should defer this call until after all the input has been collected.
 | ||||||
|  |     Finalize(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SoftwareKeyboard::DrawScreenKeyboard() { | ||||||
|  |     auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1); | ||||||
|  |     auto info = bottom_screen->framebuffer_info[bottom_screen->index]; | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
 | ||||||
|  |     memset(Memory::GetPointer(info.address_left), 0, info.stride * 320); | ||||||
|  | 
 | ||||||
|  |     GSP_GPU::SetBufferSwap(1, info); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SoftwareKeyboard::Finalize() { | ||||||
|  |     // Let the application know that we're closing
 | ||||||
|  |     Service::APT::MessageParameter message; | ||||||
|  |     message.buffer_size = sizeof(SoftwareKeyboardConfig); | ||||||
|  |     message.data = reinterpret_cast<u8*>(&config); | ||||||
|  |     message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); | ||||||
|  |     message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||||||
|  |     message.sender_id = static_cast<u32>(id); | ||||||
|  |     Service::APT::SendParameter(message); | ||||||
|  | 
 | ||||||
|  |     started = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } // namespace
 | ||||||
							
								
								
									
										87
									
								
								src/core/hle/applets/swkbd.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/core/hle/applets/swkbd.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,87 @@ | ||||||
|  | // Copyright 2015 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/hle/applets/applet.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/service/apt/apt.h" | ||||||
|  | 
 | ||||||
|  | namespace HLE { | ||||||
|  | namespace Applets { | ||||||
|  | 
 | ||||||
|  | struct SoftwareKeyboardConfig { | ||||||
|  |     INSERT_PADDING_WORDS(0x8); | ||||||
|  | 
 | ||||||
|  |     u16 max_text_length; ///< Maximum length of the input text
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_BYTES(0x6E); | ||||||
|  | 
 | ||||||
|  |     char16_t display_text[65]; ///< Text to display when asking the user for input
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_BYTES(0xE); | ||||||
|  | 
 | ||||||
|  |     u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x3); | ||||||
|  | 
 | ||||||
|  |     u32 shared_memory_size; ///< Size of the SharedMemory
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x1); | ||||||
|  | 
 | ||||||
|  |     u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_WORDS(0x2); | ||||||
|  | 
 | ||||||
|  |     u32 text_offset; ///< Offset in the SharedMemory where the output text starts
 | ||||||
|  |     u16 text_length; ///< Length in characters of the output text
 | ||||||
|  | 
 | ||||||
|  |     INSERT_PADDING_BYTES(0x2B6); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * The size of this structure (0x400) has been verified via reverse engineering of multiple games | ||||||
|  |  * that use the software keyboard. | ||||||
|  |  */ | ||||||
|  | static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); | ||||||
|  | 
 | ||||||
|  | class SoftwareKeyboard final : public Applet { | ||||||
|  | public: | ||||||
|  |     SoftwareKeyboard(Service::APT::AppletId id); | ||||||
|  |     ~SoftwareKeyboard() {} | ||||||
|  | 
 | ||||||
|  |     ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||||||
|  |     ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||||||
|  |     void Update() override; | ||||||
|  |     bool IsRunning() const override { return started; } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Draws a keyboard to the current bottom screen framebuffer. | ||||||
|  |      */ | ||||||
|  |     void DrawScreenKeyboard(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Sends the LibAppletClosing signal to the application, | ||||||
|  |      * along with the relevant data buffers. | ||||||
|  |      */ | ||||||
|  |     void Finalize(); | ||||||
|  | 
 | ||||||
|  |     /// TODO(Subv): Find out what this is actually used for.
 | ||||||
|  |     /// It is believed that the application stores the current screen image here.
 | ||||||
|  |     Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||||||
|  | 
 | ||||||
|  |     /// SharedMemory where the output text will be stored
 | ||||||
|  |     Kernel::SharedPtr<Kernel::SharedMemory> text_memory; | ||||||
|  | 
 | ||||||
|  |     /// Configuration of this instance of the SoftwareKeyboard, as received from the application
 | ||||||
|  |     SoftwareKeyboardConfig config; | ||||||
|  | 
 | ||||||
|  |     /// Whether this applet is currently running instead of the host application or not.
 | ||||||
|  |     bool started; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } // namespace
 | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| 
 | 
 | ||||||
|  | #include "core/hle/applets/applet.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "core/hle/service/apt/apt.h" | #include "core/hle/service/apt/apt.h" | ||||||
| #include "core/hle/service/apt/apt_a.h" | #include "core/hle/service/apt/apt_a.h" | ||||||
|  | @ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | ||||||
| 
 | 
 | ||||||
| static Kernel::SharedPtr<Kernel::Mutex> lock; | static Kernel::SharedPtr<Kernel::Mutex> lock; | ||||||
| static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
 | ||||||
| static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
 | static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
 | ||||||
| 
 | 
 | ||||||
| static std::vector<u8> shared_font; | static std::vector<u8> shared_font; | ||||||
| 
 | 
 | ||||||
| static u32 cpu_percent; ///< CPU time available to the running application
 | static u32 cpu_percent; ///< CPU time available to the running application
 | ||||||
| 
 | 
 | ||||||
|  | /// Parameter data to be returned in the next call to Glance/ReceiveParameter
 | ||||||
|  | static MessageParameter next_parameter; | ||||||
|  | 
 | ||||||
|  | void SendParameter(const MessageParameter& parameter) { | ||||||
|  |     next_parameter = parameter; | ||||||
|  |     // Signal the event to let the application know that a new parameter is ready to be read
 | ||||||
|  |     parameter_event->Signal(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Initialize(Service::Interface* self) { | void Initialize(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|  | @ -47,18 +57,18 @@ void Initialize(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
|     cmd_buff[2] = IPC::MoveHandleDesc(2); |     cmd_buff[2] = IPC::MoveHandleDesc(2); | ||||||
|     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); |     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | ||||||
|     cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); |     cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Check if these events are cleared every time Initialize is called.
 |     // TODO(bunnei): Check if these events are cleared every time Initialize is called.
 | ||||||
|     notification_event->Clear(); |     notification_event->Clear(); | ||||||
|     start_event->Clear(); |     parameter_event->Clear(); | ||||||
| 
 | 
 | ||||||
|     ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); |     ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); | ||||||
|     lock->Release(); |     lock->Release(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); |     LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetSharedFont(Service::Interface* self) { | void GetSharedFont(Service::Interface* self) { | ||||||
|  | @ -85,9 +95,6 @@ void GetSharedFont(Service::Interface* self) { | ||||||
| void NotifyToWait(Service::Interface* self) { | void NotifyToWait(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|     // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
 |  | ||||||
|     start_event->Signal(); |  | ||||||
| 
 |  | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | ||||||
| } | } | ||||||
|  | @ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
|     // Not sure what these parameters are used for, but retail apps check that they are 0 after
 |     // Not sure what these parameters are used for, but retail apps check that they are 0 after
 | ||||||
|     // GetLockHandle has been called.
 |     // GetLockHandle has been called.
 | ||||||
|     cmd_buff[2] = 0; |     cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable.
 | ||||||
|     cmd_buff[3] = 0; |     cmd_buff[3] = 0; | ||||||
|     cmd_buff[4] = 0; |     cmd_buff[4] = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
| void Enable(Service::Interface* self) { | void Enable(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
 |     u32 attributes = cmd_buff[1]; | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |     parameter_event->Signal(); // Let the application know that it has been started
 | ||||||
|  |     LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GetAppletManInfo(Service::Interface* self) { | void GetAppletManInfo(Service::Interface* self) { | ||||||
|  | @ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) { | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     cmd_buff[2] = 0; |     cmd_buff[2] = 0; | ||||||
|     cmd_buff[3] = 0; |     cmd_buff[3] = 0; | ||||||
|     cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID
 |     cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
 | ||||||
|     cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly
 |     cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); |     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | ||||||
| } | } | ||||||
|  | @ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     cmd_buff[2] = 1; // Set to registered
 |     /// TODO(Subv): It is currently unknown what this value (0x400) means,
 | ||||||
|  |     /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
 | ||||||
|  |     /// any LibApplet currently running. This is not verified.
 | ||||||
|  |     if (app_id != 0x400) | ||||||
|  |         cmd_buff[2] = 1; // Set to registered
 | ||||||
|  |     else | ||||||
|  |         cmd_buff[2] = 0; // Set to not registered
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); |     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
| void SendParameter(Service::Interface* self) { | void SendParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 src_app_id          = cmd_buff[1]; |     u32 src_app_id     = cmd_buff[1]; | ||||||
|     u32 dst_app_id          = cmd_buff[2]; |     u32 dst_app_id     = cmd_buff[2]; | ||||||
|     u32 signal_type         = cmd_buff[3]; |     u32 signal_type    = cmd_buff[3]; | ||||||
|     u32 buffer_size         = cmd_buff[4]; |     u32 buffer_size    = cmd_buff[4]; | ||||||
|     u32 value               = cmd_buff[5]; |     u32 value          = cmd_buff[5]; | ||||||
|     u32 handle              = cmd_buff[6]; |     u32 handle         = cmd_buff[6]; | ||||||
|     u32 size                = cmd_buff[7]; |     u32 size           = cmd_buff[7]; | ||||||
|     u32 in_param_buffer_ptr = cmd_buff[8]; |     u32 buffer         = cmd_buff[8]; | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); | ||||||
|  | 
 | ||||||
|  |     if (dest_applet == nullptr) { | ||||||
|  |         LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); | ||||||
|  |         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MessageParameter param; | ||||||
|  |     param.buffer_size = buffer_size; | ||||||
|  |     param.destination_id = dst_app_id; | ||||||
|  |     param.sender_id = src_app_id; | ||||||
|  |     param.object = Kernel::g_handle_table.GetGeneric(handle); | ||||||
|  |     param.signal = signal_type; | ||||||
|  |     param.data = Memory::GetPointer(buffer); | ||||||
|  | 
 | ||||||
|  |     cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," |     LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | ||||||
|                "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", |                "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", | ||||||
|                src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); |                src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReceiveParameter(Service::Interface* self) { | void ReceiveParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|     u32 buffer_size = cmd_buff[2]; |     u32 buffer_size = cmd_buff[2]; | ||||||
|  |     VAddr buffer = cmd_buff[0x104 >> 2]; | ||||||
|  | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     cmd_buff[2] = 0; |     cmd_buff[2] = next_parameter.sender_id; | ||||||
|     cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
 |     cmd_buff[3] = next_parameter.signal; // Signal type
 | ||||||
|     cmd_buff[4] = 0x10; // Parameter buffer size (16)
 |     cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
 | ||||||
|     cmd_buff[5] = 0; |     cmd_buff[5] = 0x10; | ||||||
|     cmd_buff[6] = 0; |     cmd_buff[6] = 0; | ||||||
|     cmd_buff[7] = 0; |     if (next_parameter.object != nullptr) | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | ||||||
|  |     cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; | ||||||
|  |     cmd_buff[8] = buffer; | ||||||
|  | 
 | ||||||
|  |     if (next_parameter.data) | ||||||
|  |         memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); | ||||||
|  | 
 | ||||||
|  |     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GlanceParameter(Service::Interface* self) { | void GlanceParameter(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 app_id = cmd_buff[1]; |     u32 app_id = cmd_buff[1]; | ||||||
|     u32 buffer_size = cmd_buff[2]; |     u32 buffer_size = cmd_buff[2]; | ||||||
|  |     VAddr buffer = cmd_buff[0x104 >> 2]; | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
|     cmd_buff[2] = 0; |     cmd_buff[2] = next_parameter.sender_id; | ||||||
|     cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
 |     cmd_buff[3] = next_parameter.signal; // Signal type
 | ||||||
|     cmd_buff[4] = 0x10; // Parameter buffer size (16)
 |     cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
 | ||||||
|     cmd_buff[5] = 0; |     cmd_buff[5] = 0x10; | ||||||
|     cmd_buff[6] = 0; |     cmd_buff[6] = 0; | ||||||
|     cmd_buff[7] = 0; |     if (next_parameter.object != nullptr) | ||||||
|  |         cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); | ||||||
|  |     cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; | ||||||
|  |     cmd_buff[8] = buffer; | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); |     if (next_parameter.data) | ||||||
|  |         memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); | ||||||
|  | 
 | ||||||
|  |     LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CancelParameter(Service::Interface* self) { | void CancelParameter(Service::Interface* self) { | ||||||
|  | @ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     // These are from 3dbrew - I'm not really sure what they're used for.
 |     // These are from 3dbrew - I'm not really sure what they're used for.
 | ||||||
|     u32 unk = cmd_buff[1]; |     u32 command = cmd_buff[1]; | ||||||
|     u32 buffer1_size = cmd_buff[2]; |     u32 buffer1_size = cmd_buff[2]; | ||||||
|     u32 buffer2_size = cmd_buff[3]; |     u32 buffer2_size = cmd_buff[3]; | ||||||
|     u32 buffer1_addr = cmd_buff[5]; |     u32 buffer1_addr = cmd_buff[5]; | ||||||
|  | @ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) { | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " |     LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " | ||||||
|              "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, |              "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size, | ||||||
|              buffer1_addr, buffer2_addr); |              buffer1_addr, buffer2_addr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -281,11 +327,41 @@ void GetAppCpuTimeLimit(Service::Interface* self) { | ||||||
|     LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); |     LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void PrepareToStartLibraryApplet(Service::Interface* self) { | ||||||
|  |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|  |     AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | ||||||
|  |     cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw; | ||||||
|  |     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void StartLibraryApplet(Service::Interface* self) { | ||||||
|  |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|  |     AppletId applet_id = static_cast<AppletId>(cmd_buff[1]); | ||||||
|  |     std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||||||
|  | 
 | ||||||
|  |     if (applet == nullptr) { | ||||||
|  |         LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id); | ||||||
|  |         cmd_buff[1] = -1; // TODO(Subv): Find the right error code
 | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     AppletStartupParameter parameter; | ||||||
|  |     parameter.buffer_size = cmd_buff[2]; | ||||||
|  |     parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); | ||||||
|  |     parameter.data = Memory::GetPointer(cmd_buff[6]); | ||||||
|  | 
 | ||||||
|  |     cmd_buff[1] = applet->Start(parameter).raw; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Init() { | void Init() { | ||||||
|     AddService(new APT_A_Interface); |     AddService(new APT_A_Interface); | ||||||
|     AddService(new APT_S_Interface); |     AddService(new APT_S_Interface); | ||||||
|     AddService(new APT_U_Interface); |     AddService(new APT_U_Interface); | ||||||
| 
 | 
 | ||||||
|  |     HLE::Applets::Init(); | ||||||
|  | 
 | ||||||
|     // Load the shared system font (if available).
 |     // Load the shared system font (if available).
 | ||||||
|     // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
 |     // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
 | ||||||
|     // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
 |     // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
 | ||||||
|  | @ -318,7 +394,10 @@ void Init() { | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
 |     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
 | ||||||
|     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); |     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); | ||||||
|     start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); |     parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); | ||||||
|  | 
 | ||||||
|  |     next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted); | ||||||
|  |     next_parameter.destination_id = 0x300; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|  | @ -326,7 +405,8 @@ void Shutdown() { | ||||||
|     shared_font_mem = nullptr; |     shared_font_mem = nullptr; | ||||||
|     lock = nullptr; |     lock = nullptr; | ||||||
|     notification_event = nullptr; |     notification_event = nullptr; | ||||||
|     start_event = nullptr; |     parameter_event = nullptr; | ||||||
|  |     HLE::Applets::Shutdown(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace APT
 | } // namespace APT
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,23 @@ | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace APT { | namespace APT { | ||||||
| 
 | 
 | ||||||
|  | /// Holds information about the parameters used in Send/Glance/ReceiveParameter
 | ||||||
|  | struct MessageParameter { | ||||||
|  |     u32 sender_id = 0; | ||||||
|  |     u32 destination_id = 0; | ||||||
|  |     u32 signal = 0; | ||||||
|  |     u32 buffer_size = 0; | ||||||
|  |     Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||||||
|  |     u8* data = nullptr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// Holds information about the parameters used in StartLibraryApplet
 | ||||||
|  | struct AppletStartupParameter { | ||||||
|  |     u32 buffer_size = 0; | ||||||
|  |     Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||||||
|  |     u8* data = nullptr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /// Signals used by APT functions
 | /// Signals used by APT functions
 | ||||||
| enum class SignalType : u32 { | enum class SignalType : u32 { | ||||||
|     None              = 0x0, |     None              = 0x0, | ||||||
|  | @ -23,7 +40,7 @@ enum class SignalType : u32 { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// App Id's used by APT functions
 | /// App Id's used by APT functions
 | ||||||
| enum class AppID : u32 { | enum class AppletId : u32 { | ||||||
|     HomeMenu           = 0x101, |     HomeMenu           = 0x101, | ||||||
|     AlternateMenu      = 0x103, |     AlternateMenu      = 0x103, | ||||||
|     Camera             = 0x110, |     Camera             = 0x110, | ||||||
|  | @ -45,6 +62,9 @@ enum class AppID : u32 { | ||||||
|     SoftwareKeyboard2  = 0x401, |     SoftwareKeyboard2  = 0x401, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /// Send a parameter to the currently-running application, which will read it via ReceiveParameter
 | ||||||
|  | void SendParameter(const MessageParameter& parameter); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * APT::Initialize service function |  * APT::Initialize service function | ||||||
|  * Service function that initializes the APT process for the running application |  * Service function that initializes the APT process for the running application | ||||||
|  | @ -249,6 +269,33 @@ void SetAppCpuTimeLimit(Service::Interface* self); | ||||||
|  */ |  */ | ||||||
| void GetAppCpuTimeLimit(Service::Interface* self); | void GetAppCpuTimeLimit(Service::Interface* self); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * APT::PrepareToStartLibraryApplet service function | ||||||
|  |  *  Inputs: | ||||||
|  |  *      0 : Command header [0x00180040] | ||||||
|  |  *      1 : Id of the applet to start | ||||||
|  |  *  Outputs: | ||||||
|  |  *      0 : Return header | ||||||
|  |  *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | void PrepareToStartLibraryApplet(Service::Interface* self); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * APT::StartLibraryApplet service function | ||||||
|  |  *  Inputs: | ||||||
|  |  *      0 : Command header [0x001E0084] | ||||||
|  |  *      1 : Id of the applet to start | ||||||
|  |  *      2 : Buffer size | ||||||
|  |  *      3 : Always 0? | ||||||
|  |  *      4 : Handle passed to the applet | ||||||
|  |  *      5 : (Size << 14) | 2 | ||||||
|  |  *      6 : Input buffer virtual address | ||||||
|  |  *  Outputs: | ||||||
|  |  *      0 : Return header | ||||||
|  |  *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |  */ | ||||||
|  | void StartLibraryApplet(Service::Interface* self); | ||||||
|  | 
 | ||||||
| /// Initialize the APT service
 | /// Initialize the APT service
 | ||||||
| void Init(); | void Init(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,19 +10,24 @@ namespace Service { | ||||||
| namespace APT { | namespace APT { | ||||||
| 
 | 
 | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x00010040, GetLockHandle,      "GetLockHandle?"}, |     {0x00010040, GetLockHandle,                "GetLockHandle?"}, | ||||||
|     {0x00020080, Initialize,         "Initialize?"}, |     {0x00020080, Initialize,                   "Initialize?"}, | ||||||
|     {0x00030040, Enable,             "Enable?"}, |     {0x00030040, Enable,                       "Enable?"}, | ||||||
|     {0x00040040, nullptr,            "Finalize?"}, |     {0x00040040, nullptr,                      "Finalize?"}, | ||||||
|     {0x00050040, nullptr,            "GetAppletManInfo?"}, |     {0x00050040, nullptr,                      "GetAppletManInfo?"}, | ||||||
|     {0x00060040, nullptr,            "GetAppletInfo?"}, |     {0x00060040, nullptr,                      "GetAppletInfo?"}, | ||||||
|     {0x000D0080, ReceiveParameter,   "ReceiveParameter?"}, |     {0x00090040, IsRegistered,                 "IsRegistered"}, | ||||||
|     {0x000E0080, GlanceParameter,    "GlanceParameter?"}, |     {0x000C0104, SendParameter,                "SendParameter"}, | ||||||
|     {0x003B0040, nullptr,            "CancelLibraryApplet?"}, |     {0x000D0080, ReceiveParameter,             "ReceiveParameter"}, | ||||||
|     {0x00430040, NotifyToWait,       "NotifyToWait?"}, |     {0x000E0080, GlanceParameter,              "GlanceParameter"}, | ||||||
|     {0x00440000, GetSharedFont,      "GetSharedFont?"}, |     {0x000F0100, CancelParameter,              "CancelParameter"}, | ||||||
|     {0x004B00C2, AppletUtility,      "AppletUtility?"}, |     {0x00180040, PrepareToStartLibraryApplet,  "PrepareToStartLibraryApplet"}, | ||||||
|     {0x00550040, nullptr,            "WriteInputToNsState?"}, |     {0x001E0084, StartLibraryApplet,           "StartLibraryApplet"}, | ||||||
|  |     {0x003B0040, nullptr,                      "CancelLibraryApplet?"}, | ||||||
|  |     {0x00430040, NotifyToWait,                 "NotifyToWait?"}, | ||||||
|  |     {0x00440000, GetSharedFont,                "GetSharedFont?"}, | ||||||
|  |     {0x004B00C2, AppletUtility,                "AppletUtility?"}, | ||||||
|  |     {0x00550040, nullptr,                      "WriteInputToNsState?"}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| APT_A_Interface::APT_A_Interface() { | APT_A_Interface::APT_A_Interface() { | ||||||
|  |  | ||||||
|  | @ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = { | ||||||
|     {0x00150140, nullptr,                         "PrepareToStartApplication"}, |     {0x00150140, nullptr,                         "PrepareToStartApplication"}, | ||||||
|     {0x00160040, nullptr,                         "PreloadLibraryApplet"}, |     {0x00160040, nullptr,                         "PreloadLibraryApplet"}, | ||||||
|     {0x00170040, nullptr,                         "FinishPreloadingLibraryApplet"}, |     {0x00170040, nullptr,                         "FinishPreloadingLibraryApplet"}, | ||||||
|     {0x00180040, nullptr,                         "PrepareToStartLibraryApplet"}, |     {0x00180040, PrepareToStartLibraryApplet,     "PrepareToStartLibraryApplet"}, | ||||||
|     {0x00190040, nullptr,                         "PrepareToStartSystemApplet"}, |     {0x00190040, nullptr,                         "PrepareToStartSystemApplet"}, | ||||||
|     {0x001A0000, nullptr,                         "PrepareToStartNewestHomeMenu"}, |     {0x001A0000, nullptr,                         "PrepareToStartNewestHomeMenu"}, | ||||||
|     {0x001B00C4, nullptr,                         "StartApplication"}, |     {0x001B00C4, nullptr,                         "StartApplication"}, | ||||||
|     {0x001C0000, nullptr,                         "WakeupApplication"}, |     {0x001C0000, nullptr,                         "WakeupApplication"}, | ||||||
|     {0x001D0000, nullptr,                         "CancelApplication"}, |     {0x001D0000, nullptr,                         "CancelApplication"}, | ||||||
|     {0x001E0084, nullptr,                         "StartLibraryApplet"}, |     {0x001E0084, StartLibraryApplet,              "StartLibraryApplet"}, | ||||||
|     {0x001F0084, nullptr,                         "StartSystemApplet"}, |     {0x001F0084, nullptr,                         "StartSystemApplet"}, | ||||||
|     {0x00200044, nullptr,                         "StartNewestHomeMenu"}, |     {0x00200044, nullptr,                         "StartNewestHomeMenu"}, | ||||||
|     {0x00210000, nullptr,                         "OrderToCloseApplication"}, |     {0x00210000, nullptr,                         "OrderToCloseApplication"}, | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) { | ||||||
|     return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); |     return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { | FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { | ||||||
|     DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); |     DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); | ||||||
| 
 | 
 | ||||||
|     // For each thread there are two FrameBufferUpdate fields
 |     // For each thread there are two FrameBufferUpdate fields
 | ||||||
|  | @ -205,7 +205,7 @@ static void ReadHWRegs(Service::Interface* self) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { | ||||||
|     u32 base_address = 0x400000; |     u32 base_address = 0x400000; | ||||||
|     PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); |     PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); | ||||||
|     PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); |     PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); | ||||||
|  |  | ||||||
|  | @ -173,4 +173,14 @@ public: | ||||||
|  */ |  */ | ||||||
| void SignalInterrupt(InterruptId interrupt_id); | void SignalInterrupt(InterruptId interrupt_id); | ||||||
| 
 | 
 | ||||||
|  | void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Retrieves the framebuffer info stored in the GSP shared memory for the | ||||||
|  |  * specified screen index and thread id. | ||||||
|  |  * @param thread_id GSP thread id of the process that accesses the structure that we are requesting. | ||||||
|  |  * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1). | ||||||
|  |  * @returns FramebufferUpdate Information about the specified framebuffer. | ||||||
|  |  */ | ||||||
|  | FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index); | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue