From 2caf04e6da36478142d64db03b18d4cbf40dc5bc Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Thu, 6 Jun 2024 13:45:33 -0400 Subject: [PATCH] Move controller implementations from librecomp to ultramodern (#38) * Start moving some cont functions to ultramodern * Implement osContStartQuery, osContSetCh * Finish moving cont.cpp functions to ultramodern * Add constexpr to _return * Fix rumble not working * Rename cont.cpp to input.cpp * Test --- librecomp/include/librecomp/game.hpp | 2 +- librecomp/include/librecomp/helpers.hpp | 12 +- librecomp/src/cont.cpp | 146 ++++++------------ librecomp/src/recomp.cpp | 6 +- ultramodern/CMakeLists.txt | 1 + ultramodern/include/ultramodern/input.hpp | 22 +++ ultramodern/include/ultramodern/ultra64.h | 59 +++++++ .../include/ultramodern/ultramodern.hpp | 14 +- ultramodern/src/input.cpp | 144 +++++++++++++++++ ultramodern/src/ultrainit.cpp | 4 +- 10 files changed, 287 insertions(+), 123 deletions(-) create mode 100644 ultramodern/include/ultramodern/input.hpp create mode 100644 ultramodern/src/input.cpp diff --git a/librecomp/include/librecomp/game.hpp b/librecomp/include/librecomp/game.hpp index 5a65997..5bcfaca 100644 --- a/librecomp/include/librecomp/game.hpp +++ b/librecomp/include/librecomp/game.hpp @@ -41,7 +41,7 @@ namespace recomp { void set_rom_contents(std::vector&& new_rom); void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes); void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr); - void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); + void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); void start_game(const std::u8string& game_id); std::u8string current_game_id(); } diff --git a/librecomp/include/librecomp/helpers.hpp b/librecomp/include/librecomp/helpers.hpp index 1562b99..9f02367 100644 --- a/librecomp/include/librecomp/helpers.hpp +++ b/librecomp/include/librecomp/helpers.hpp @@ -39,12 +39,18 @@ T _arg(uint8_t* rdram, recomp_context* ctx) { template void _return(recomp_context* ctx, T val) { static_assert(sizeof(T) <= 4 && "Only 32-bit value returns supported currently"); - if (std::is_same_v) { + if constexpr (std::is_same_v) { ctx->f0.fl = val; } - else if (std::is_integral_v && sizeof(T) <= 4) { + else if constexpr (std::is_integral_v && sizeof(T) <= 4) { ctx->r2 = int32_t(val); } + else { + // static_assert in else workaround + [] () { + static_assert(flag, "Unsupported type"); + }(); + } } -#endif \ No newline at end of file +#endif diff --git a/librecomp/src/cont.cpp b/librecomp/src/cont.cpp index fe56c66..0ca9686 100644 --- a/librecomp/src/cont.cpp +++ b/librecomp/src/cont.cpp @@ -1,14 +1,7 @@ -#include +#include "ultramodern/ultramodern.hpp" + #include "helpers.hpp" -static ultramodern::input_callbacks_t input_callbacks; - -std::chrono::high_resolution_clock::time_point input_poll_time; - -void update_poll_time() { - input_poll_time = std::chrono::high_resolution_clock::now(); -} - extern "C" void recomp_set_current_frame_poll_id(uint8_t* rdram, recomp_context* ctx) { // TODO reimplement the system for tagging polls with IDs to handle games with multithreaded input polling. } @@ -17,139 +10,92 @@ extern "C" void recomp_measure_latency(uint8_t* rdram, recomp_context* ctx) { ultramodern::measure_input_latency(); } -void ultramodern::measure_input_latency() { - // printf("Delta: %ld micros\n", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - input_poll_time)); -} - -void set_input_callbacks(const ultramodern::input_callbacks_t& callbacks) { - input_callbacks = callbacks; -} - -static int max_controllers = 0; - extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) bitpattern = _arg<1, PTR(void)>(rdram, ctx); - PTR(void) status = _arg<2, PTR(void)>(rdram, ctx); + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); + PTR(u8) bitpattern = _arg<1, PTR(u8)>(rdram, ctx); + PTR(OSContStatus) data = _arg<2, PTR(OSContStatus)>(rdram, ctx); - // Set bit 0 to indicate that controller 0 is present - MEM_B(0, bitpattern) = 0x01; + s32 ret = osContInit(PASS_RDRAM mq, bitpattern, data); - // Mark controller 0 as present - MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus) - MEM_B(2, status) = 0x00; // status: 0 (from joybus) - MEM_B(3, status) = 0x00; // errno: 0 (from libultra) + _return(ctx, ret); +} - max_controllers = 4; +extern "C" void osContReset_recomp(uint8_t* rdram, recomp_context* ctx) { + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); + PTR(OSContStatus) data = _arg<1, PTR(OSContStatus)>(rdram, ctx); - // Mark controllers 1-3 as not connected - for (size_t controller = 1; controller < max_controllers; controller++) { - // Libultra doesn't write status or type for absent controllers - MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 - } + s32 ret = osContReset(PASS_RDRAM mq, data); - _return(ctx, 0); + _return(ctx, ret); } extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) { - if (input_callbacks.poll_input) { - input_callbacks.poll_input(); - } - update_poll_time(); + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); - ultramodern::send_si_message(rdram); + s32 ret = osContStartReadData(PASS_RDRAM mq); + + _return(ctx, ret); } extern "C" void osContGetReadData_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pad = _arg<0, PTR(void)>(rdram, ctx); + PTR(OSContPad) data = _arg<0, PTR(OSContPad)>(rdram, ctx); - uint16_t buttons = 0; - float x = 0.0f; - float y = 0.0f; - - if (input_callbacks.get_input) { - input_callbacks.get_input(&buttons, &x, &y); - } - - if (max_controllers > 0) { - // button - MEM_H(0, pad) = buttons; - // stick_x - MEM_B(2, pad) = (int8_t)(127 * x); - // stick_y - MEM_B(3, pad) = (int8_t)(127 * y); - // errno - MEM_B(4, pad) = 0; - } - for (int controller = 1; controller < max_controllers; controller++) { - MEM_B(6 * controller + 4, pad) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 - } + osContGetReadData(PASS_RDRAM data); } extern "C" void osContStartQuery_recomp(uint8_t * rdram, recomp_context * ctx) { - ultramodern::send_si_message(rdram); + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); + + s32 ret = osContStartQuery(PASS_RDRAM mq); + + _return(ctx, ret); } extern "C" void osContGetQuery_recomp(uint8_t * rdram, recomp_context * ctx) { - PTR(void) status = _arg<0, PTR(void)>(rdram, ctx); + PTR(OSContStatus) data = _arg<0, PTR(OSContStatus)>(rdram, ctx); - // Mark controller 0 as present - MEM_H(0, status) = 0x0005; // type: CONT_TYPE_NORMAL (from joybus) - MEM_B(2, status) = 0x01; // status: 0x01 (from joybus, indicates that a pak is plugged into the controller) - MEM_B(3, status) = 0x00; // errno: 0 (from libultra) - - // Mark controllers 1-3 as not connected - for (size_t controller = 1; controller < max_controllers; controller++) { - // Libultra doesn't write status or type for absent controllers - MEM_B(4 * controller + 3, status) = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 - } + osContGetQuery(PASS_RDRAM data); } extern "C" void osContSetCh_recomp(uint8_t* rdram, recomp_context* ctx) { - max_controllers = (std::min)(_arg<0, u8>(rdram, ctx), u8(4)); - _return(ctx, 0); + u8 ch = _arg<0, u8>(rdram, ctx); + + s32 ret = osContSetCh(PASS_RDRAM ch); + + _return(ctx, ret); } extern "C" void __osMotorAccess_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); s32 flag = _arg<1, s32>(rdram, ctx); - s32 channel = MEM_W(8, pfs); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(flag); - } + s32 ret = __osMotorAccess(PASS_RDRAM pfs, flag); - _return(ctx, 0); + _return(ctx, ret); } extern "C" void osMotorInit_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<1, PTR(void)>(rdram, ctx); - s32 channel = _arg<2, s32>(rdram, ctx); - MEM_W(8, pfs) = channel; + PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx); + PTR(OSPfs) pfs = _arg<1, PTR(OSPfs)>(rdram, ctx); + int channel = _arg<2, s32>(rdram, ctx); - _return(ctx, 0); + s32 ret = osMotorInit(PASS_RDRAM mq, pfs, channel); + + _return(ctx, ret); } extern "C" void osMotorStart_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); - s32 channel = MEM_W(8, pfs); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(true); - } + s32 ret = osMotorStart(PASS_RDRAM pfs); - _return(ctx, 0); + _return(ctx, ret); } extern "C" void osMotorStop_recomp(uint8_t* rdram, recomp_context* ctx) { - PTR(void) pfs = _arg<0, PTR(void)>(rdram, ctx); - s32 channel = MEM_W(8, pfs); + PTR(OSPfs) pfs = _arg<0, PTR(OSPfs)>(rdram, ctx); - // Only respect accesses to controller 0. - if (channel == 0) { - input_callbacks.set_rumble(false); - } + s32 ret = osMotorStop(PASS_RDRAM pfs); - _return(ctx, 0); + _return(ctx, ret); } diff --git a/librecomp/src/recomp.cpp b/librecomp/src/recomp.cpp index db80bbf..df52937 100644 --- a/librecomp/src/recomp.cpp +++ b/librecomp/src/recomp.cpp @@ -379,8 +379,6 @@ bool ultramodern::is_game_started() { return game_status.load() != GameStatus::None; } -void set_input_callbacks(const ultramodern::input_callbacks_t& callback); - std::atomic_bool exited = false; void ultramodern::quit() { @@ -392,7 +390,7 @@ void ultramodern::quit() { current_game.reset(); } -void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { +void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input::callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { recomp::check_all_stored_roms(); recomp::rsp::set_callbacks(rsp_callbacks); @@ -404,8 +402,6 @@ void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::c ultramodern::set_callbacks(ultramodern_rsp_callbacks, audio_callbacks, input_callbacks, gfx_callbacks_, thread_callbacks_, error_handling_callbacks_); - set_input_callbacks(input_callbacks); - ultramodern::gfx_callbacks_t gfx_callbacks = gfx_callbacks_; ultramodern::gfx_callbacks_t::gfx_data_t gfx_data{}; diff --git a/ultramodern/CMakeLists.txt b/ultramodern/CMakeLists.txt index 336fd16..23276d5 100644 --- a/ultramodern/CMakeLists.txt +++ b/ultramodern/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(ultramodern STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/error_handling.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/input.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/rsp.cpp" diff --git a/ultramodern/include/ultramodern/input.hpp b/ultramodern/include/ultramodern/input.hpp new file mode 100644 index 0000000..efbe5e8 --- /dev/null +++ b/ultramodern/include/ultramodern/input.hpp @@ -0,0 +1,22 @@ +#ifndef __ULTRAMODERN_INPUT_HPP__ +#define __ULTRAMODERN_INPUT_HPP__ + +#include + +namespace ultramodern { + namespace input { + struct callbacks_t { + using poll_input_t = void(void); + using get_input_t = void(uint16_t*, float*, float*); + using set_rumble_t = void(bool); + + poll_input_t* poll_input; + get_input_t* get_input; + set_rumble_t* set_rumble; + }; + + void set_callbacks(const callbacks_t& callbacks); + } +} + +#endif diff --git a/ultramodern/include/ultramodern/ultra64.h b/ultramodern/include/ultramodern/ultra64.h index 395cadb..a737a45 100644 --- a/ultramodern/include/ultramodern/ultra64.h +++ b/ultramodern/include/ultramodern/ultra64.h @@ -214,6 +214,48 @@ typedef struct { OSViFieldRegs fldRegs[2]; } OSViMode; +/* + * Structure for file system + */ +typedef struct { + int status; + PTR(OSMesgQueue) queue; + int channel; + u8 id[32]; // TODO: funky endianness here + u8 label[32]; // TODO: funky endianness here + int version; + int dir_size; + int inode_table; /* block location */ + int minode_table; /* mirrioring inode_table */ + int dir_table; /* block location */ + int inode_start_page; /* page # */ + // Padding and reversed members due to endianness + u8 padding[2]; + u8 activebank; + u8 banks; +} OSPfs; + + +// Controller + +typedef struct { + // These three members reversed due to endianness + u8 err_no; + u8 status; /* Controller status */ + u16 type; /* Controller Type */ +} OSContStatus; + +typedef struct { + // These three members reversed due to endianness + s8 stick_y; /* -80 <= stick_y <= 80 */ + s8 stick_x; /* -80 <= stick_x <= 80 */ + u16 button; + // Padding due to endianness + u8 padding[3]; + u8 err_no; +} OSContPad; + + /////////////// // Functions // /////////////// @@ -255,6 +297,23 @@ int osSetTimer(RDRAM_ARG PTR(OSTimer) timer, OSTime countdown, OSTime interval, int osStopTimer(RDRAM_ARG PTR(OSTimer) timer); u32 osVirtualToPhysical(PTR(void) addr); +/* Controller interface */ + +s32 osContInit(RDRAM_ARG PTR(OSMesgQueue), PTR(u8), PTR(OSContStatus)); +s32 osContReset(RDRAM_ARG PTR(OSMesgQueue), PTR(OSContStatus)); +s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue)); +s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue)); +s32 osContSetCh(RDRAM_ARG u8); +void osContGetQuery(RDRAM_ARG PTR(OSContStatus)); +void osContGetReadData(RDRAM_ARG PTR(OSContPad)); + +/* Rumble PAK interface */ + +s32 osMotorInit(RDRAM_ARG PTR(OSMesgQueue), PTR(OSPfs), int); +s32 osMotorStop(RDRAM_ARG PTR(OSPfs)); +s32 osMotorStart(RDRAM_ARG PTR(OSPfs)); +s32 __osMotorAccess(RDRAM_ARG PTR(OSPfs), s32); + #ifdef __cplusplus } // extern "C" #endif diff --git a/ultramodern/include/ultramodern/ultramodern.hpp b/ultramodern/include/ultramodern/ultramodern.hpp index 871abee..3649cd6 100644 --- a/ultramodern/include/ultramodern/ultramodern.hpp +++ b/ultramodern/include/ultramodern/ultramodern.hpp @@ -27,6 +27,7 @@ #include "ultramodern/error_handling.hpp" #include "ultramodern/events.hpp" +#include "ultramodern/input.hpp" #include "ultramodern/rsp.hpp" struct UltraThreadContext { @@ -142,17 +143,6 @@ struct audio_callbacks_t { set_frequency_t* set_frequency; }; -// TODO: These functions are currently called by librecomp, but will get called by ultramodern in the future -// Input -struct input_callbacks_t { - using poll_input_t = void(void); - using get_input_t = void(uint16_t*, float*, float*); - using set_rumble_t = void(bool); - poll_input_t* poll_input; - get_input_t* get_input; - set_rumble_t* set_rumble; -}; - // TODO: Most of the members of this struct are not used by ultramodern. Should we move them to librecomp instead? struct gfx_callbacks_t { using gfx_data_t = void*; @@ -178,7 +168,7 @@ void set_audio_callbacks(const audio_callbacks_t& callbacks); * * It must be called only once and it must be called before `ultramodern::preinit`. */ -void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks); +void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input::callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& events_callbacks, const error_handling::callbacks_t& error_handling_callbacks); } // namespace ultramodern #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/ultramodern/src/input.cpp b/ultramodern/src/input.cpp new file mode 100644 index 0000000..5a6010f --- /dev/null +++ b/ultramodern/src/input.cpp @@ -0,0 +1,144 @@ +#include + +#include "ultramodern/input.hpp" +#include "ultramodern/ultra64.h" +#include "ultramodern/ultramodern.hpp" + +static ultramodern::input::callbacks_t input_callbacks {}; + +void ultramodern::input::set_callbacks(const callbacks_t& callbacks) { + input_callbacks = callbacks; +} + +static std::chrono::high_resolution_clock::time_point input_poll_time; + +static void update_poll_time() { + input_poll_time = std::chrono::high_resolution_clock::now(); +} + +void ultramodern::measure_input_latency() { +#if 0 + printf("Delta: %ld micros\n", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - input_poll_time)); +#endif +} + +#define MAXCONTROLLERS 4 + +static int max_controllers = 0; + +/* Plain controller */ + +static void __osContGetInitData(u8* pattern, OSContStatus *data) { + // Set bit 0 to indicate that controller 0 is present + *pattern = 0x01; + + // Mark controller 0 as present + data[0].type = 0x0005; // type: CONT_TYPE_NORMAL (from joybus) + data[0].status = 0x01; // status: 0x01 (from joybus, indicates that a pak is plugged into the controller) + data[0].err_no = 0x00; // errno: 0 (from libultra) + + // Mark controllers 1-3 as not connected + for (int controller = 1; controller < max_controllers; controller++) { + // Libultra doesn't write status or type for absent controllers + data[controller].err_no = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 + } +} + +extern "C" s32 osContInit(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(u8) bitpattern_, PTR(OSContStatus) data_) { + u8 *bitpattern = TO_PTR(u8, bitpattern_); + OSContStatus *data = TO_PTR(OSContStatus, data_); + + max_controllers = MAXCONTROLLERS; + + __osContGetInitData(bitpattern, data); + + return 0; +} + +extern "C" s32 osContReset(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(OSContStatus) data) { + assert(false); + return 0; +} + +extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) { + ultramodern::send_si_message(PASS_RDRAM1); + + return 0; +} + +extern "C" s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue) mq) { + if (input_callbacks.poll_input != nullptr) { + input_callbacks.poll_input(); + } + update_poll_time(); + + ultramodern::send_si_message(rdram); + + return 0; +} + +extern "C" s32 osContSetCh(RDRAM_ARG u8 ch) { + max_controllers = std::min(ch, u8(MAXCONTROLLERS)); + + return 0; +} + +extern "C" void osContGetQuery(RDRAM_ARG PTR(OSContStatus) data_) { + OSContStatus *data = TO_PTR(OSContStatus, data_); + u8 pattern; + + __osContGetInitData(&pattern, data); +} + +extern "C" void osContGetReadData(RDRAM_ARG PTR(OSContPad) data_) { + OSContPad *data = TO_PTR(OSContPad, data_); + uint16_t buttons = 0; + float x = 0.0f; + float y = 0.0f; + + if (input_callbacks.get_input != nullptr) { + input_callbacks.get_input(&buttons, &x, &y); + } + + if (max_controllers > 0) { + // button + data[0].button = buttons; + data[0].stick_x = (int8_t)(127 * x); + data[0].stick_y = (int8_t)(127 * y); + data[0].err_no = 0; + } + for (int controller = 1; controller < max_controllers; controller++) { + data[controller].err_no = 0x80 >> 4; // errno: CONT_NO_RESPONSE_ERROR >> 4 + } +} + +/* Rumble */ + +s32 osMotorInit(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(OSPfs) pfs_, int channel) { + OSPfs *pfs = TO_PTR(OSPfs, pfs_); + + pfs->channel = channel; + + return 0; +} + +s32 osMotorStop(RDRAM_ARG PTR(OSPfs) pfs) { + return __osMotorAccess(PASS_RDRAM pfs, false); +} + +s32 osMotorStart(RDRAM_ARG PTR(OSPfs) pfs) { + return __osMotorAccess(PASS_RDRAM pfs, true); +} + +s32 __osMotorAccess(RDRAM_ARG PTR(OSPfs) pfs_, s32 flag) { + OSPfs *pfs = TO_PTR(OSPfs, pfs_); + + // Only respect accesses to controller 0. + if (pfs->channel == 0) { + if (input_callbacks.set_rumble != nullptr) { + input_callbacks.set_rumble(flag); + } + } + + return 0; +} diff --git a/ultramodern/src/ultrainit.cpp b/ultramodern/src/ultrainit.cpp index 4fca62a..1517b77 100644 --- a/ultramodern/src/ultrainit.cpp +++ b/ultramodern/src/ultrainit.cpp @@ -4,14 +4,14 @@ void ultramodern::set_callbacks( const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, - const input_callbacks_t& input_callbacks, + const input::callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& thread_callbacks, const error_handling::callbacks_t& error_handling_callbacks ) { ultramodern::rsp::set_callbacks(rsp_callbacks); ultramodern::set_audio_callbacks(audio_callbacks); - (void)input_callbacks; // nothing yet + ultramodern::input::set_callbacks(input_callbacks); (void)gfx_callbacks; // nothing yet ultramodern::events::set_callbacks(thread_callbacks); ultramodern::error_handling::set_callbacks(error_handling_callbacks);