diff options
| author | 2017-10-10 17:32:14 -0400 | |
|---|---|---|
| committer | 2017-10-10 17:32:14 -0400 | |
| commit | 0906de9a14b735d1d409290ca050eb7d2c2d3d84 (patch) | |
| tree | 79bb57d3a4dc4ca377e7a62744c3941de29e785b | |
| parent | Merge remote-tracking branch 'upstream/master' into nx (diff) | |
| download | yuzu-0906de9a14b735d1d409290ca050eb7d2c2d3d84.tar.gz yuzu-0906de9a14b735d1d409290ca050eb7d2c2d3d84.tar.xz yuzu-0906de9a14b735d1d409290ca050eb7d2c2d3d84.zip | |
hle: Remove a large amount of 3ds-specific service code.
200 files changed, 2 insertions, 22393 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 45c28ad09..432bf2ced 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -134,21 +134,6 @@ void Config::ReadValues() { | |||
| 134 | Settings::values.region_value = | 134 | Settings::values.region_value = |
| 135 | sdl2_config->GetInteger("System", "region_value", Settings::REGION_VALUE_AUTO_SELECT); | 135 | sdl2_config->GetInteger("System", "region_value", Settings::REGION_VALUE_AUTO_SELECT); |
| 136 | 136 | ||
| 137 | // Camera | ||
| 138 | using namespace Service::CAM; | ||
| 139 | Settings::values.camera_name[OuterRightCamera] = | ||
| 140 | sdl2_config->Get("Camera", "camera_outer_right_name", "blank"); | ||
| 141 | Settings::values.camera_config[OuterRightCamera] = | ||
| 142 | sdl2_config->Get("Camera", "camera_outer_right_config", ""); | ||
| 143 | Settings::values.camera_name[InnerCamera] = | ||
| 144 | sdl2_config->Get("Camera", "camera_inner_name", "blank"); | ||
| 145 | Settings::values.camera_config[InnerCamera] = | ||
| 146 | sdl2_config->Get("Camera", "camera_inner_config", ""); | ||
| 147 | Settings::values.camera_name[OuterLeftCamera] = | ||
| 148 | sdl2_config->Get("Camera", "camera_outer_left_name", "blank"); | ||
| 149 | Settings::values.camera_config[OuterLeftCamera] = | ||
| 150 | sdl2_config->Get("Camera", "camera_outer_left_config", ""); | ||
| 151 | |||
| 152 | // Miscellaneous | 137 | // Miscellaneous |
| 153 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info"); | 138 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info"); |
| 154 | 139 | ||
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 59faf773f..783c4a835 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -153,22 +153,6 @@ is_new_3ds = | |||
| 153 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | 153 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan |
| 154 | region_value = | 154 | region_value = |
| 155 | 155 | ||
| 156 | [Camera] | ||
| 157 | # Which camera engine to use for the right outer camera | ||
| 158 | # blank (default): a dummy camera that always returns black image | ||
| 159 | camera_outer_right_name = | ||
| 160 | |||
| 161 | # A config string for the right outer camera. Its meaning is defined by the camera engine | ||
| 162 | camera_outer_right_config = | ||
| 163 | |||
| 164 | # ... for the left outer camera | ||
| 165 | camera_outer_left_name = | ||
| 166 | camera_outer_left_config = | ||
| 167 | |||
| 168 | # ... for the inner camera | ||
| 169 | camera_inner_name = | ||
| 170 | camera_inner_config = | ||
| 171 | |||
| 172 | [Miscellaneous] | 156 | [Miscellaneous] |
| 173 | # A filter which removes logs below a certain logging level. | 157 | # A filter which removes logs below a certain logging level. |
| 174 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | 158 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical |
diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 5261f4c4c..c268e0068 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp | |||
| @@ -105,22 +105,6 @@ void Config::ReadValues() { | |||
| 105 | qt_config->value("output_device", "auto").toString().toStdString(); | 105 | qt_config->value("output_device", "auto").toString().toStdString(); |
| 106 | qt_config->endGroup(); | 106 | qt_config->endGroup(); |
| 107 | 107 | ||
| 108 | using namespace Service::CAM; | ||
| 109 | qt_config->beginGroup("Camera"); | ||
| 110 | Settings::values.camera_name[OuterRightCamera] = | ||
| 111 | qt_config->value("camera_outer_right_name", "blank").toString().toStdString(); | ||
| 112 | Settings::values.camera_config[OuterRightCamera] = | ||
| 113 | qt_config->value("camera_outer_right_config", "").toString().toStdString(); | ||
| 114 | Settings::values.camera_name[InnerCamera] = | ||
| 115 | qt_config->value("camera_inner_name", "blank").toString().toStdString(); | ||
| 116 | Settings::values.camera_config[InnerCamera] = | ||
| 117 | qt_config->value("camera_inner_config", "").toString().toStdString(); | ||
| 118 | Settings::values.camera_name[OuterLeftCamera] = | ||
| 119 | qt_config->value("camera_outer_left_name", "blank").toString().toStdString(); | ||
| 120 | Settings::values.camera_config[OuterLeftCamera] = | ||
| 121 | qt_config->value("camera_outer_left_config", "").toString().toStdString(); | ||
| 122 | qt_config->endGroup(); | ||
| 123 | |||
| 124 | qt_config->beginGroup("Data Storage"); | 108 | qt_config->beginGroup("Data Storage"); |
| 125 | Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); | 109 | Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); |
| 126 | qt_config->endGroup(); | 110 | qt_config->endGroup(); |
| @@ -259,22 +243,6 @@ void Config::SaveValues() { | |||
| 259 | qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id)); | 243 | qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id)); |
| 260 | qt_config->endGroup(); | 244 | qt_config->endGroup(); |
| 261 | 245 | ||
| 262 | using namespace Service::CAM; | ||
| 263 | qt_config->beginGroup("Camera"); | ||
| 264 | qt_config->setValue("camera_outer_right_name", | ||
| 265 | QString::fromStdString(Settings::values.camera_name[OuterRightCamera])); | ||
| 266 | qt_config->setValue("camera_outer_right_config", | ||
| 267 | QString::fromStdString(Settings::values.camera_config[OuterRightCamera])); | ||
| 268 | qt_config->setValue("camera_inner_name", | ||
| 269 | QString::fromStdString(Settings::values.camera_name[InnerCamera])); | ||
| 270 | qt_config->setValue("camera_inner_config", | ||
| 271 | QString::fromStdString(Settings::values.camera_config[InnerCamera])); | ||
| 272 | qt_config->setValue("camera_outer_left_name", | ||
| 273 | QString::fromStdString(Settings::values.camera_name[OuterLeftCamera])); | ||
| 274 | qt_config->setValue("camera_outer_left_config", | ||
| 275 | QString::fromStdString(Settings::values.camera_config[OuterLeftCamera])); | ||
| 276 | qt_config->endGroup(); | ||
| 277 | |||
| 278 | qt_config->beginGroup("Data Storage"); | 246 | qt_config->beginGroup("Data Storage"); |
| 279 | qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); | 247 | qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); |
| 280 | qt_config->endGroup(); | 248 | qt_config->endGroup(); |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 4b83eeb28..1361ccfba 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -33,32 +33,11 @@ namespace Log { | |||
| 33 | SUB(Kernel, SVC) \ | 33 | SUB(Kernel, SVC) \ |
| 34 | CLS(Service) \ | 34 | CLS(Service) \ |
| 35 | SUB(Service, SRV) \ | 35 | SUB(Service, SRV) \ |
| 36 | SUB(Service, FRD) \ | ||
| 37 | SUB(Service, FS) \ | 36 | SUB(Service, FS) \ |
| 38 | SUB(Service, ERR) \ | ||
| 39 | SUB(Service, APT) \ | ||
| 40 | SUB(Service, BOSS) \ | ||
| 41 | SUB(Service, GSP) \ | 37 | SUB(Service, GSP) \ |
| 42 | SUB(Service, AC) \ | ||
| 43 | SUB(Service, AM) \ | ||
| 44 | SUB(Service, PTM) \ | ||
| 45 | SUB(Service, LDR) \ | ||
| 46 | SUB(Service, MIC) \ | ||
| 47 | SUB(Service, NDM) \ | ||
| 48 | SUB(Service, NFC) \ | ||
| 49 | SUB(Service, NIM) \ | ||
| 50 | SUB(Service, NWM) \ | ||
| 51 | SUB(Service, CAM) \ | ||
| 52 | SUB(Service, CECD) \ | ||
| 53 | SUB(Service, CFG) \ | 38 | SUB(Service, CFG) \ |
| 54 | SUB(Service, CSND) \ | ||
| 55 | SUB(Service, DSP) \ | 39 | SUB(Service, DSP) \ |
| 56 | SUB(Service, DLP) \ | ||
| 57 | SUB(Service, HID) \ | 40 | SUB(Service, HID) \ |
| 58 | SUB(Service, HTTP) \ | ||
| 59 | SUB(Service, SOC) \ | ||
| 60 | SUB(Service, IR) \ | ||
| 61 | SUB(Service, Y2R) \ | ||
| 62 | CLS(HW) \ | 41 | CLS(HW) \ |
| 63 | SUB(HW, Memory) \ | 42 | SUB(HW, Memory) \ |
| 64 | SUB(HW, LCD) \ | 43 | SUB(HW, LCD) \ |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index fe4dfed69..2ebd8911c 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -50,32 +50,11 @@ enum class Class : ClassType { | |||
| 50 | Service, ///< HLE implementation of system services. Each major service | 50 | Service, ///< HLE implementation of system services. Each major service |
| 51 | /// should have its own subclass. | 51 | /// should have its own subclass. |
| 52 | Service_SRV, ///< The SRV (Service Directory) implementation | 52 | Service_SRV, ///< The SRV (Service Directory) implementation |
| 53 | Service_FRD, ///< The FRD (Friends) service | ||
| 54 | Service_FS, ///< The FS (Filesystem) service implementation | 53 | Service_FS, ///< The FS (Filesystem) service implementation |
| 55 | Service_ERR, ///< The ERR (Error) port implementation | ||
| 56 | Service_APT, ///< The APT (Applets) service | ||
| 57 | Service_BOSS, ///< The BOSS (SpotPass) service | ||
| 58 | Service_GSP, ///< The GSP (GPU control) service | 54 | Service_GSP, ///< The GSP (GPU control) service |
| 59 | Service_AC, ///< The AC (WiFi status) service | ||
| 60 | Service_AM, ///< The AM (Application manager) service | ||
| 61 | Service_PTM, ///< The PTM (Power status & misc.) service | ||
| 62 | Service_LDR, ///< The LDR (3ds dll loader) service | ||
| 63 | Service_MIC, ///< The MIC (Microphone) service | ||
| 64 | Service_NDM, ///< The NDM (Network daemon manager) service | ||
| 65 | Service_NFC, ///< The NFC service | ||
| 66 | Service_NIM, ///< The NIM (Network interface manager) service | ||
| 67 | Service_NWM, ///< The NWM (Network wlan manager) service | ||
| 68 | Service_CAM, ///< The CAM (Camera) service | ||
| 69 | Service_CECD, ///< The CECD (StreetPass) service | ||
| 70 | Service_CFG, ///< The CFG (Configuration) service | 55 | Service_CFG, ///< The CFG (Configuration) service |
| 71 | Service_CSND, ///< The CSND (CWAV format process) service | ||
| 72 | Service_DSP, ///< The DSP (DSP control) service | 56 | Service_DSP, ///< The DSP (DSP control) service |
| 73 | Service_DLP, ///< The DLP (Download Play) service | ||
| 74 | Service_HID, ///< The HID (Human interface device) service | 57 | Service_HID, ///< The HID (Human interface device) service |
| 75 | Service_HTTP, ///< The HTTP service | ||
| 76 | Service_SOC, ///< The SOC (Socket) service | ||
| 77 | Service_IR, ///< The IR service | ||
| 78 | Service_Y2R, ///< The Y2R (YUV to RGB conversion) service | ||
| 79 | HW, ///< Low-level hardware emulation | 58 | HW, ///< Low-level hardware emulation |
| 80 | HW_Memory, ///< Memory-map and address translation | 59 | HW_Memory, ///< Memory-map and address translation |
| 81 | HW_LCD, ///< LCD register emulation | 60 | HW_LCD, ///< LCD register emulation |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8b25eaf0a..fa0379946 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -32,18 +32,10 @@ set(SRCS | |||
| 32 | file_sys/path_parser.cpp | 32 | file_sys/path_parser.cpp |
| 33 | file_sys/savedata_archive.cpp | 33 | file_sys/savedata_archive.cpp |
| 34 | file_sys/title_metadata.cpp | 34 | file_sys/title_metadata.cpp |
| 35 | frontend/camera/blank_camera.cpp | ||
| 36 | frontend/camera/factory.cpp | ||
| 37 | frontend/camera/interface.cpp | ||
| 38 | frontend/emu_window.cpp | 35 | frontend/emu_window.cpp |
| 39 | frontend/framebuffer_layout.cpp | 36 | frontend/framebuffer_layout.cpp |
| 40 | gdbstub/gdbstub.cpp | 37 | gdbstub/gdbstub.cpp |
| 41 | hle/config_mem.cpp | 38 | hle/config_mem.cpp |
| 42 | hle/applets/applet.cpp | ||
| 43 | hle/applets/erreula.cpp | ||
| 44 | hle/applets/mii_selector.cpp | ||
| 45 | hle/applets/mint.cpp | ||
| 46 | hle/applets/swkbd.cpp | ||
| 47 | hle/kernel/address_arbiter.cpp | 39 | hle/kernel/address_arbiter.cpp |
| 48 | hle/kernel/client_port.cpp | 40 | hle/kernel/client_port.cpp |
| 49 | hle/kernel/client_session.cpp | 41 | hle/kernel/client_session.cpp |
| @@ -65,49 +57,12 @@ set(SRCS | |||
| 65 | hle/kernel/wait_object.cpp | 57 | hle/kernel/wait_object.cpp |
| 66 | hle/lock.cpp | 58 | hle/lock.cpp |
| 67 | hle/romfs.cpp | 59 | hle/romfs.cpp |
| 68 | hle/service/ac/ac.cpp | ||
| 69 | hle/service/ac/ac_i.cpp | ||
| 70 | hle/service/ac/ac_u.cpp | ||
| 71 | hle/service/act/act.cpp | ||
| 72 | hle/service/act/act_a.cpp | ||
| 73 | hle/service/act/act_u.cpp | ||
| 74 | hle/service/am/am.cpp | ||
| 75 | hle/service/am/am_app.cpp | ||
| 76 | hle/service/am/am_net.cpp | ||
| 77 | hle/service/am/am_sys.cpp | ||
| 78 | hle/service/am/am_u.cpp | ||
| 79 | hle/service/apt/apt.cpp | ||
| 80 | hle/service/apt/apt_a.cpp | ||
| 81 | hle/service/apt/apt_s.cpp | ||
| 82 | hle/service/apt/apt_u.cpp | ||
| 83 | hle/service/apt/bcfnt/bcfnt.cpp | ||
| 84 | hle/service/boss/boss.cpp | ||
| 85 | hle/service/boss/boss_p.cpp | ||
| 86 | hle/service/boss/boss_u.cpp | ||
| 87 | hle/service/cam/cam.cpp | ||
| 88 | hle/service/cam/cam_c.cpp | ||
| 89 | hle/service/cam/cam_q.cpp | ||
| 90 | hle/service/cam/cam_s.cpp | ||
| 91 | hle/service/cam/cam_u.cpp | ||
| 92 | hle/service/cecd/cecd.cpp | ||
| 93 | hle/service/cecd/cecd_ndm.cpp | ||
| 94 | hle/service/cecd/cecd_s.cpp | ||
| 95 | hle/service/cecd/cecd_u.cpp | ||
| 96 | hle/service/cfg/cfg.cpp | 60 | hle/service/cfg/cfg.cpp |
| 97 | hle/service/cfg/cfg_i.cpp | 61 | hle/service/cfg/cfg_i.cpp |
| 98 | hle/service/cfg/cfg_nor.cpp | 62 | hle/service/cfg/cfg_nor.cpp |
| 99 | hle/service/cfg/cfg_s.cpp | 63 | hle/service/cfg/cfg_s.cpp |
| 100 | hle/service/cfg/cfg_u.cpp | 64 | hle/service/cfg/cfg_u.cpp |
| 101 | hle/service/csnd_snd.cpp | ||
| 102 | hle/service/dlp/dlp.cpp | ||
| 103 | hle/service/dlp/dlp_clnt.cpp | ||
| 104 | hle/service/dlp/dlp_fkcl.cpp | ||
| 105 | hle/service/dlp/dlp_srvr.cpp | ||
| 106 | hle/service/dsp_dsp.cpp | 65 | hle/service/dsp_dsp.cpp |
| 107 | hle/service/err_f.cpp | ||
| 108 | hle/service/frd/frd.cpp | ||
| 109 | hle/service/frd/frd_a.cpp | ||
| 110 | hle/service/frd/frd_u.cpp | ||
| 111 | hle/service/fs/archive.cpp | 66 | hle/service/fs/archive.cpp |
| 112 | hle/service/fs/fs_user.cpp | 67 | hle/service/fs/fs_user.cpp |
| 113 | hle/service/gsp_gpu.cpp | 68 | hle/service/gsp_gpu.cpp |
| @@ -115,60 +70,11 @@ set(SRCS | |||
| 115 | hle/service/hid/hid.cpp | 70 | hle/service/hid/hid.cpp |
| 116 | hle/service/hid/hid_spvr.cpp | 71 | hle/service/hid/hid_spvr.cpp |
| 117 | hle/service/hid/hid_user.cpp | 72 | hle/service/hid/hid_user.cpp |
| 118 | hle/service/http_c.cpp | ||
| 119 | hle/service/ir/extra_hid.cpp | ||
| 120 | hle/service/ir/ir.cpp | ||
| 121 | hle/service/ir/ir_rst.cpp | ||
| 122 | hle/service/ir/ir_u.cpp | ||
| 123 | hle/service/ir/ir_user.cpp | ||
| 124 | hle/service/ldr_ro/cro_helper.cpp | ||
| 125 | hle/service/ldr_ro/ldr_ro.cpp | ||
| 126 | hle/service/ldr_ro/memory_synchronizer.cpp | ||
| 127 | hle/service/mic_u.cpp | ||
| 128 | hle/service/mvd/mvd.cpp | ||
| 129 | hle/service/mvd/mvd_std.cpp | ||
| 130 | hle/service/ndm/ndm.cpp | ||
| 131 | hle/service/ndm/ndm_u.cpp | ||
| 132 | hle/service/nfc/nfc.cpp | ||
| 133 | hle/service/nfc/nfc_m.cpp | ||
| 134 | hle/service/nfc/nfc_u.cpp | ||
| 135 | hle/service/news/news.cpp | ||
| 136 | hle/service/news/news_s.cpp | ||
| 137 | hle/service/news/news_u.cpp | ||
| 138 | hle/service/nim/nim.cpp | ||
| 139 | hle/service/nim/nim_aoc.cpp | ||
| 140 | hle/service/nim/nim_s.cpp | ||
| 141 | hle/service/nim/nim_u.cpp | ||
| 142 | hle/service/ns/ns.cpp | 73 | hle/service/ns/ns.cpp |
| 143 | hle/service/ns/ns_s.cpp | 74 | hle/service/ns/ns_s.cpp |
| 144 | hle/service/nwm/nwm.cpp | ||
| 145 | hle/service/nwm/nwm_cec.cpp | ||
| 146 | hle/service/nwm/nwm_ext.cpp | ||
| 147 | hle/service/nwm/nwm_inf.cpp | ||
| 148 | hle/service/nwm/nwm_sap.cpp | ||
| 149 | hle/service/nwm/nwm_soc.cpp | ||
| 150 | hle/service/nwm/nwm_tst.cpp | ||
| 151 | hle/service/nwm/nwm_uds.cpp | ||
| 152 | hle/service/nwm/uds_beacon.cpp | ||
| 153 | hle/service/nwm/uds_connection.cpp | ||
| 154 | hle/service/nwm/uds_data.cpp | ||
| 155 | hle/service/pm_app.cpp | ||
| 156 | hle/service/ptm/ptm.cpp | ||
| 157 | hle/service/ptm/ptm_gets.cpp | ||
| 158 | hle/service/ptm/ptm_play.cpp | ||
| 159 | hle/service/ptm/ptm_sets.cpp | ||
| 160 | hle/service/ptm/ptm_sysm.cpp | ||
| 161 | hle/service/ptm/ptm_u.cpp | ||
| 162 | hle/service/qtm/qtm.cpp | ||
| 163 | hle/service/qtm/qtm_s.cpp | ||
| 164 | hle/service/qtm/qtm_sp.cpp | ||
| 165 | hle/service/qtm/qtm_u.cpp | ||
| 166 | hle/service/service.cpp | 75 | hle/service/service.cpp |
| 167 | hle/service/sm/sm.cpp | 76 | hle/service/sm/sm.cpp |
| 168 | hle/service/sm/srv.cpp | 77 | hle/service/sm/srv.cpp |
| 169 | hle/service/soc_u.cpp | ||
| 170 | hle/service/ssl_c.cpp | ||
| 171 | hle/service/y2r_u.cpp | ||
| 172 | hle/shared_page.cpp | 78 | hle/shared_page.cpp |
| 173 | hle/svc.cpp | 79 | hle/svc.cpp |
| 174 | hw/aes/arithmetic128.cpp | 80 | hw/aes/arithmetic128.cpp |
| @@ -177,7 +83,6 @@ set(SRCS | |||
| 177 | hw/gpu.cpp | 83 | hw/gpu.cpp |
| 178 | hw/hw.cpp | 84 | hw/hw.cpp |
| 179 | hw/lcd.cpp | 85 | hw/lcd.cpp |
| 180 | hw/y2r.cpp | ||
| 181 | loader/3dsx.cpp | 86 | loader/3dsx.cpp |
| 182 | loader/elf.cpp | 87 | loader/elf.cpp |
| 183 | loader/linker.cpp | 88 | loader/linker.cpp |
| @@ -231,9 +136,6 @@ set(HEADERS | |||
| 231 | file_sys/ivfc_archive.h | 136 | file_sys/ivfc_archive.h |
| 232 | file_sys/path_parser.h | 137 | file_sys/path_parser.h |
| 233 | file_sys/savedata_archive.h | 138 | file_sys/savedata_archive.h |
| 234 | frontend/camera/blank_camera.h | ||
| 235 | frontend/camera/factory.h | ||
| 236 | frontend/camera/interface.h | ||
| 237 | frontend/emu_window.h | 139 | frontend/emu_window.h |
| 238 | frontend/framebuffer_layout.h | 140 | frontend/framebuffer_layout.h |
| 239 | frontend/input.h | 141 | frontend/input.h |
| @@ -242,11 +144,6 @@ set(HEADERS | |||
| 242 | hle/function_wrappers.h | 144 | hle/function_wrappers.h |
| 243 | hle/ipc.h | 145 | hle/ipc.h |
| 244 | hle/ipc_helpers.h | 146 | hle/ipc_helpers.h |
| 245 | hle/applets/applet.h | ||
| 246 | hle/applets/erreula.h | ||
| 247 | hle/applets/mii_selector.h | ||
| 248 | hle/applets/mint.h | ||
| 249 | hle/applets/swkbd.h | ||
| 250 | hle/kernel/address_arbiter.h | 147 | hle/kernel/address_arbiter.h |
| 251 | hle/kernel/client_port.h | 148 | hle/kernel/client_port.h |
| 252 | hle/kernel/client_session.h | 149 | hle/kernel/client_session.h |
| @@ -271,49 +168,12 @@ set(HEADERS | |||
| 271 | hle/lock.h | 168 | hle/lock.h |
| 272 | hle/result.h | 169 | hle/result.h |
| 273 | hle/romfs.h | 170 | hle/romfs.h |
| 274 | hle/service/ac/ac.h | ||
| 275 | hle/service/ac/ac_i.h | ||
| 276 | hle/service/ac/ac_u.h | ||
| 277 | hle/service/act/act.h | ||
| 278 | hle/service/act/act_a.h | ||
| 279 | hle/service/act/act_u.h | ||
| 280 | hle/service/am/am.h | ||
| 281 | hle/service/am/am_app.h | ||
| 282 | hle/service/am/am_net.h | ||
| 283 | hle/service/am/am_sys.h | ||
| 284 | hle/service/am/am_u.h | ||
| 285 | hle/service/apt/apt.h | ||
| 286 | hle/service/apt/apt_a.h | ||
| 287 | hle/service/apt/apt_s.h | ||
| 288 | hle/service/apt/apt_u.h | ||
| 289 | hle/service/apt/bcfnt/bcfnt.h | ||
| 290 | hle/service/boss/boss.h | ||
| 291 | hle/service/boss/boss_p.h | ||
| 292 | hle/service/boss/boss_u.h | ||
| 293 | hle/service/cam/cam.h | ||
| 294 | hle/service/cam/cam_c.h | ||
| 295 | hle/service/cam/cam_q.h | ||
| 296 | hle/service/cam/cam_s.h | ||
| 297 | hle/service/cam/cam_u.h | ||
| 298 | hle/service/cecd/cecd.h | ||
| 299 | hle/service/cecd/cecd_ndm.h | ||
| 300 | hle/service/cecd/cecd_s.h | ||
| 301 | hle/service/cecd/cecd_u.h | ||
| 302 | hle/service/cfg/cfg.h | 171 | hle/service/cfg/cfg.h |
| 303 | hle/service/cfg/cfg_i.h | 172 | hle/service/cfg/cfg_i.h |
| 304 | hle/service/cfg/cfg_nor.h | 173 | hle/service/cfg/cfg_nor.h |
| 305 | hle/service/cfg/cfg_s.h | 174 | hle/service/cfg/cfg_s.h |
| 306 | hle/service/cfg/cfg_u.h | 175 | hle/service/cfg/cfg_u.h |
| 307 | hle/service/csnd_snd.h | ||
| 308 | hle/service/dlp/dlp.h | ||
| 309 | hle/service/dlp/dlp_clnt.h | ||
| 310 | hle/service/dlp/dlp_fkcl.h | ||
| 311 | hle/service/dlp/dlp_srvr.h | ||
| 312 | hle/service/dsp_dsp.h | 176 | hle/service/dsp_dsp.h |
| 313 | hle/service/err_f.h | ||
| 314 | hle/service/frd/frd.h | ||
| 315 | hle/service/frd/frd_a.h | ||
| 316 | hle/service/frd/frd_u.h | ||
| 317 | hle/service/fs/archive.h | 177 | hle/service/fs/archive.h |
| 318 | hle/service/fs/fs_user.h | 178 | hle/service/fs/fs_user.h |
| 319 | hle/service/gsp_gpu.h | 179 | hle/service/gsp_gpu.h |
| @@ -321,60 +181,11 @@ set(HEADERS | |||
| 321 | hle/service/hid/hid.h | 181 | hle/service/hid/hid.h |
| 322 | hle/service/hid/hid_spvr.h | 182 | hle/service/hid/hid_spvr.h |
| 323 | hle/service/hid/hid_user.h | 183 | hle/service/hid/hid_user.h |
| 324 | hle/service/http_c.h | ||
| 325 | hle/service/ir/extra_hid.h | ||
| 326 | hle/service/ir/ir.h | ||
| 327 | hle/service/ir/ir_rst.h | ||
| 328 | hle/service/ir/ir_u.h | ||
| 329 | hle/service/ir/ir_user.h | ||
| 330 | hle/service/ldr_ro/cro_helper.h | ||
| 331 | hle/service/ldr_ro/ldr_ro.h | ||
| 332 | hle/service/ldr_ro/memory_synchronizer.h | ||
| 333 | hle/service/mic_u.h | ||
| 334 | hle/service/mvd/mvd.h | ||
| 335 | hle/service/mvd/mvd_std.h | ||
| 336 | hle/service/ndm/ndm.h | ||
| 337 | hle/service/ndm/ndm_u.h | ||
| 338 | hle/service/nfc/nfc.h | ||
| 339 | hle/service/nfc/nfc_m.h | ||
| 340 | hle/service/nfc/nfc_u.h | ||
| 341 | hle/service/news/news.h | ||
| 342 | hle/service/news/news_s.h | ||
| 343 | hle/service/news/news_u.h | ||
| 344 | hle/service/nim/nim.h | ||
| 345 | hle/service/nim/nim_aoc.h | ||
| 346 | hle/service/nim/nim_s.h | ||
| 347 | hle/service/nim/nim_u.h | ||
| 348 | hle/service/ns/ns.h | 184 | hle/service/ns/ns.h |
| 349 | hle/service/ns/ns_s.h | 185 | hle/service/ns/ns_s.h |
| 350 | hle/service/nwm/nwm.h | ||
| 351 | hle/service/nwm/nwm_cec.h | ||
| 352 | hle/service/nwm/nwm_ext.h | ||
| 353 | hle/service/nwm/nwm_inf.h | ||
| 354 | hle/service/nwm/nwm_sap.h | ||
| 355 | hle/service/nwm/nwm_soc.h | ||
| 356 | hle/service/nwm/nwm_tst.h | ||
| 357 | hle/service/nwm/nwm_uds.h | ||
| 358 | hle/service/nwm/uds_beacon.h | ||
| 359 | hle/service/nwm/uds_connection.h | ||
| 360 | hle/service/nwm/uds_data.h | ||
| 361 | hle/service/pm_app.h | ||
| 362 | hle/service/ptm/ptm.h | ||
| 363 | hle/service/ptm/ptm_gets.h | ||
| 364 | hle/service/ptm/ptm_play.h | ||
| 365 | hle/service/ptm/ptm_sets.h | ||
| 366 | hle/service/ptm/ptm_sysm.h | ||
| 367 | hle/service/ptm/ptm_u.h | ||
| 368 | hle/service/qtm/qtm.h | ||
| 369 | hle/service/qtm/qtm_s.h | ||
| 370 | hle/service/qtm/qtm_sp.h | ||
| 371 | hle/service/qtm/qtm_u.h | ||
| 372 | hle/service/service.h | 186 | hle/service/service.h |
| 373 | hle/service/sm/sm.h | 187 | hle/service/sm/sm.h |
| 374 | hle/service/sm/srv.h | 188 | hle/service/sm/srv.h |
| 375 | hle/service/soc_u.h | ||
| 376 | hle/service/ssl_c.h | ||
| 377 | hle/service/y2r_u.h | ||
| 378 | hle/shared_page.h | 189 | hle/shared_page.h |
| 379 | hle/svc.h | 190 | hle/svc.h |
| 380 | hw/aes/arithmetic128.h | 191 | hw/aes/arithmetic128.h |
| @@ -383,7 +194,6 @@ set(HEADERS | |||
| 383 | hw/gpu.h | 194 | hw/gpu.h |
| 384 | hw/hw.h | 195 | hw/hw.h |
| 385 | hw/lcd.h | 196 | hw/lcd.h |
| 386 | hw/y2r.h | ||
| 387 | loader/3dsx.h | 197 | loader/3dsx.h |
| 388 | loader/elf.h | 198 | loader/elf.h |
| 389 | loader/linker.h | 199 | loader/linker.h |
diff --git a/src/core/frontend/camera/blank_camera.cpp b/src/core/frontend/camera/blank_camera.cpp deleted file mode 100644 index 7995abcbd..000000000 --- a/src/core/frontend/camera/blank_camera.cpp +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/frontend/camera/blank_camera.h" | ||
| 6 | |||
| 7 | namespace Camera { | ||
| 8 | |||
| 9 | void BlankCamera::StartCapture() {} | ||
| 10 | |||
| 11 | void BlankCamera::StopCapture() {} | ||
| 12 | |||
| 13 | void BlankCamera::SetFormat(Service::CAM::OutputFormat output_format) { | ||
| 14 | output_rgb = output_format == Service::CAM::OutputFormat::RGB565; | ||
| 15 | } | ||
| 16 | |||
| 17 | void BlankCamera::SetResolution(const Service::CAM::Resolution& resolution) { | ||
| 18 | width = resolution.width; | ||
| 19 | height = resolution.height; | ||
| 20 | }; | ||
| 21 | |||
| 22 | void BlankCamera::SetFlip(Service::CAM::Flip) {} | ||
| 23 | |||
| 24 | void BlankCamera::SetEffect(Service::CAM::Effect) {} | ||
| 25 | |||
| 26 | std::vector<u16> BlankCamera::ReceiveFrame() const { | ||
| 27 | // Note: 0x80008000 stands for two black pixels in YUV422 | ||
| 28 | return std::vector<u16>(width * height, output_rgb ? 0 : 0x8000); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace Camera | ||
diff --git a/src/core/frontend/camera/blank_camera.h b/src/core/frontend/camera/blank_camera.h deleted file mode 100644 index c6619bd88..000000000 --- a/src/core/frontend/camera/blank_camera.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/frontend/camera/factory.h" | ||
| 8 | #include "core/frontend/camera/interface.h" | ||
| 9 | |||
| 10 | namespace Camera { | ||
| 11 | |||
| 12 | class BlankCamera final : public CameraInterface { | ||
| 13 | public: | ||
| 14 | void StartCapture() override; | ||
| 15 | void StopCapture() override; | ||
| 16 | void SetResolution(const Service::CAM::Resolution&) override; | ||
| 17 | void SetFlip(Service::CAM::Flip) override; | ||
| 18 | void SetEffect(Service::CAM::Effect) override; | ||
| 19 | void SetFormat(Service::CAM::OutputFormat) override; | ||
| 20 | std::vector<u16> ReceiveFrame() const override; | ||
| 21 | |||
| 22 | private: | ||
| 23 | int width = 0; | ||
| 24 | int height = 0; | ||
| 25 | bool output_rgb = false; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Camera | ||
diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp deleted file mode 100644 index 4b4da50dd..000000000 --- a/src/core/frontend/camera/factory.cpp +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <unordered_map> | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/frontend/camera/blank_camera.h" | ||
| 8 | #include "core/frontend/camera/factory.h" | ||
| 9 | |||
| 10 | namespace Camera { | ||
| 11 | |||
| 12 | static std::unordered_map<std::string, std::unique_ptr<CameraFactory>> factories; | ||
| 13 | |||
| 14 | CameraFactory::~CameraFactory() = default; | ||
| 15 | |||
| 16 | void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> factory) { | ||
| 17 | factories[name] = std::move(factory); | ||
| 18 | } | ||
| 19 | |||
| 20 | std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config) { | ||
| 21 | auto pair = factories.find(name); | ||
| 22 | if (pair != factories.end()) { | ||
| 23 | return pair->second->Create(config); | ||
| 24 | } | ||
| 25 | |||
| 26 | if (name != "blank") { | ||
| 27 | LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str()); | ||
| 28 | } | ||
| 29 | return std::make_unique<BlankCamera>(); | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace Camera | ||
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h deleted file mode 100644 index f46413fa7..000000000 --- a/src/core/frontend/camera/factory.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "core/frontend/camera/interface.h" | ||
| 10 | |||
| 11 | namespace Camera { | ||
| 12 | |||
| 13 | class CameraFactory { | ||
| 14 | public: | ||
| 15 | virtual ~CameraFactory(); | ||
| 16 | |||
| 17 | /** | ||
| 18 | * Creates a camera object based on the configuration string. | ||
| 19 | * @param config Configuration string to create the camera. The implementation can decide the | ||
| 20 | * meaning of this string. | ||
| 21 | * @returns a unique_ptr to the created camera object. | ||
| 22 | */ | ||
| 23 | virtual std::unique_ptr<CameraInterface> Create(const std::string& config) const = 0; | ||
| 24 | }; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Registers an external camera factory. | ||
| 28 | * @param name Identifier of the camera factory. | ||
| 29 | * @param factory Camera factory to register. | ||
| 30 | */ | ||
| 31 | void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> factory); | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Creates a camera from the factory. | ||
| 35 | * @param name Identifier of the camera factory. | ||
| 36 | * @param config Configuration string to create the camera. The meaning of this string is | ||
| 37 | * defined by the factory. | ||
| 38 | */ | ||
| 39 | std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config); | ||
| 40 | |||
| 41 | } // namespace Camera | ||
diff --git a/src/core/frontend/camera/interface.cpp b/src/core/frontend/camera/interface.cpp deleted file mode 100644 index 9aec9e7f1..000000000 --- a/src/core/frontend/camera/interface.cpp +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/frontend/camera/interface.h" | ||
| 6 | |||
| 7 | namespace Camera { | ||
| 8 | |||
| 9 | CameraInterface::~CameraInterface() = default; | ||
| 10 | |||
| 11 | } // namespace Camera | ||
diff --git a/src/core/frontend/camera/interface.h b/src/core/frontend/camera/interface.h deleted file mode 100644 index a55a495c9..000000000 --- a/src/core/frontend/camera/interface.h +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/cam/cam.h" | ||
| 10 | |||
| 11 | namespace Camera { | ||
| 12 | |||
| 13 | /// An abstract class standing for a camera. All camera implementations should inherit from this. | ||
| 14 | class CameraInterface { | ||
| 15 | public: | ||
| 16 | virtual ~CameraInterface(); | ||
| 17 | |||
| 18 | /// Starts the camera for video capturing. | ||
| 19 | virtual void StartCapture() = 0; | ||
| 20 | |||
| 21 | /// Stops the camera for video capturing. | ||
| 22 | virtual void StopCapture() = 0; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Sets the video resolution from raw CAM service parameters. | ||
| 26 | * For the meaning of the parameters, please refer to Service::CAM::Resolution. Note that the | ||
| 27 | * actual camera implementation doesn't need to respect all the parameters. However, the width | ||
| 28 | * and the height parameters must be respected and be used to determine the size of output | ||
| 29 | * frames. | ||
| 30 | * @param resolution The resolution parameters to set | ||
| 31 | */ | ||
| 32 | virtual void SetResolution(const Service::CAM::Resolution& resolution) = 0; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Configures how received frames should be flipped by the camera. | ||
| 36 | * @param flip Flip applying to the frame | ||
| 37 | */ | ||
| 38 | virtual void SetFlip(Service::CAM::Flip flip) = 0; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Configures what effect should be applied to received frames by the camera. | ||
| 42 | * @param effect Effect applying to the frame | ||
| 43 | */ | ||
| 44 | virtual void SetEffect(Service::CAM::Effect effect) = 0; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Sets the output format of the all frames received after this function is called. | ||
| 48 | * @param format Output format of the frame | ||
| 49 | */ | ||
| 50 | virtual void SetFormat(Service::CAM::OutputFormat format) = 0; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Receives a frame from the camera. | ||
| 54 | * This function should be only called between a StartCapture call and a StopCapture call. | ||
| 55 | * @returns A std::vector<u16> containing pixels. The total size of the vector is width * height | ||
| 56 | * where width and height are set by a call to SetResolution. | ||
| 57 | */ | ||
| 58 | virtual std::vector<u16> ReceiveFrame() const = 0; | ||
| 59 | }; | ||
| 60 | |||
| 61 | } // namespace Camera | ||
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp deleted file mode 100644 index 9c43ed2fd..000000000 --- a/src/core/hle/applets/applet.cpp +++ /dev/null | |||
| @@ -1,130 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #include <memory> | ||
| 7 | #include <type_traits> | ||
| 8 | #include <unordered_map> | ||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/core_timing.h" | ||
| 12 | #include "core/hle/applets/applet.h" | ||
| 13 | #include "core/hle/applets/erreula.h" | ||
| 14 | #include "core/hle/applets/mii_selector.h" | ||
| 15 | #include "core/hle/applets/mint.h" | ||
| 16 | #include "core/hle/applets/swkbd.h" | ||
| 17 | #include "core/hle/result.h" | ||
| 18 | #include "core/hle/service/apt/apt.h" | ||
| 19 | |||
| 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 21 | |||
| 22 | // Specializes std::hash for AppletId, so that we can use it in std::unordered_map. | ||
| 23 | // Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 | ||
| 24 | namespace std { | ||
| 25 | template <> | ||
| 26 | struct hash<Service::APT::AppletId> { | ||
| 27 | typedef Service::APT::AppletId argument_type; | ||
| 28 | typedef std::size_t result_type; | ||
| 29 | |||
| 30 | result_type operator()(const argument_type& id_code) const { | ||
| 31 | typedef std::underlying_type<argument_type>::type Type; | ||
| 32 | return std::hash<Type>()(static_cast<Type>(id_code)); | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | } | ||
| 36 | |||
| 37 | namespace HLE { | ||
| 38 | namespace Applets { | ||
| 39 | |||
| 40 | static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets; | ||
| 41 | static u32 applet_update_event = | ||
| 42 | -1; ///< The CoreTiming event identifier for the Applet update callback. | ||
| 43 | /// The interval at which the Applet update callback will be called, 16.6ms | ||
| 44 | static const u64 applet_update_interval_us = 16666; | ||
| 45 | |||
| 46 | ResultCode Applet::Create(Service::APT::AppletId id) { | ||
| 47 | switch (id) { | ||
| 48 | case Service::APT::AppletId::SoftwareKeyboard1: | ||
| 49 | case Service::APT::AppletId::SoftwareKeyboard2: | ||
| 50 | applets[id] = std::make_shared<SoftwareKeyboard>(id); | ||
| 51 | break; | ||
| 52 | case Service::APT::AppletId::Ed1: | ||
| 53 | case Service::APT::AppletId::Ed2: | ||
| 54 | applets[id] = std::make_shared<MiiSelector>(id); | ||
| 55 | break; | ||
| 56 | case Service::APT::AppletId::Error: | ||
| 57 | case Service::APT::AppletId::Error2: | ||
| 58 | applets[id] = std::make_shared<ErrEula>(id); | ||
| 59 | break; | ||
| 60 | case Service::APT::AppletId::Mint: | ||
| 61 | case Service::APT::AppletId::Mint2: | ||
| 62 | applets[id] = std::make_shared<Mint>(id); | ||
| 63 | break; | ||
| 64 | default: | ||
| 65 | LOG_ERROR(Service_APT, "Could not create applet %u", id); | ||
| 66 | // TODO(Subv): Find the right error code | ||
| 67 | return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, | ||
| 68 | ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||
| 69 | } | ||
| 70 | |||
| 71 | return RESULT_SUCCESS; | ||
| 72 | } | ||
| 73 | |||
| 74 | std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) { | ||
| 75 | auto itr = applets.find(id); | ||
| 76 | if (itr != applets.end()) | ||
| 77 | return itr->second; | ||
| 78 | return nullptr; | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Handles updating the current Applet every time it's called. | ||
| 82 | static void AppletUpdateEvent(u64 applet_id, int cycles_late) { | ||
| 83 | Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); | ||
| 84 | std::shared_ptr<Applet> applet = Applet::Get(id); | ||
| 85 | ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); | ||
| 86 | |||
| 87 | applet->Update(); | ||
| 88 | |||
| 89 | // If the applet is still running after the last update, reschedule the event | ||
| 90 | if (applet->IsRunning()) { | ||
| 91 | CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, | ||
| 92 | applet_update_event, applet_id); | ||
| 93 | } else { | ||
| 94 | // Otherwise the applet has terminated, in which case we should clean it up | ||
| 95 | applets[id] = nullptr; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { | ||
| 100 | ResultCode result = StartImpl(parameter); | ||
| 101 | if (result.IsError()) | ||
| 102 | return result; | ||
| 103 | // Schedule the update event | ||
| 104 | CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, | ||
| 105 | static_cast<u64>(id)); | ||
| 106 | return result; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool Applet::IsRunning() const { | ||
| 110 | return is_running; | ||
| 111 | } | ||
| 112 | |||
| 113 | bool IsLibraryAppletRunning() { | ||
| 114 | // Check the applets map for instances of any applet | ||
| 115 | for (auto itr = applets.begin(); itr != applets.end(); ++itr) | ||
| 116 | if (itr->second != nullptr) | ||
| 117 | return true; | ||
| 118 | return false; | ||
| 119 | } | ||
| 120 | |||
| 121 | void Init() { | ||
| 122 | // Register the applet update callback | ||
| 123 | applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); | ||
| 124 | } | ||
| 125 | |||
| 126 | void Shutdown() { | ||
| 127 | CoreTiming::RemoveEvent(applet_update_event); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } // namespace | ||
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h deleted file mode 100644 index ebeed9813..000000000 --- a/src/core/hle/applets/applet.h +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/apt/apt.h" | ||
| 10 | |||
| 11 | namespace HLE { | ||
| 12 | namespace Applets { | ||
| 13 | |||
| 14 | class Applet { | ||
| 15 | public: | ||
| 16 | virtual ~Applet() = default; | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Creates an instance of the Applet subclass identified by the parameter. | ||
| 20 | * and stores it in a global map. | ||
| 21 | * @param id Id of the applet to create. | ||
| 22 | * @returns ResultCode Whether the operation was successful or not. | ||
| 23 | */ | ||
| 24 | static ResultCode Create(Service::APT::AppletId id); | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Retrieves the Applet instance identified by the specified id. | ||
| 28 | * @param id Id of the Applet to retrieve. | ||
| 29 | * @returns Requested Applet or nullptr if not found. | ||
| 30 | */ | ||
| 31 | static std::shared_ptr<Applet> Get(Service::APT::AppletId id); | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Handles a parameter from the application. | ||
| 35 | * @param parameter Parameter data to handle. | ||
| 36 | * @returns ResultCode Whether the operation was successful or not. | ||
| 37 | */ | ||
| 38 | virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Handles the Applet start event, triggered from the application. | ||
| 42 | * @param parameter Parameter data to handle. | ||
| 43 | * @returns ResultCode Whether the operation was successful or not. | ||
| 44 | */ | ||
| 45 | ResultCode Start(const Service::APT::AppletStartupParameter& parameter); | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Whether the applet is currently executing instead of the host application or not. | ||
| 49 | */ | ||
| 50 | bool IsRunning() const; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Handles an update tick for the Applet, lets it update the screen, send commands, etc. | ||
| 54 | */ | ||
| 55 | virtual void Update() = 0; | ||
| 56 | |||
| 57 | protected: | ||
| 58 | explicit Applet(Service::APT::AppletId id) : id(id) {} | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Handles the Applet start event, triggered from the application. | ||
| 62 | * @param parameter Parameter data to handle. | ||
| 63 | * @returns ResultCode Whether the operation was successful or not. | ||
| 64 | */ | ||
| 65 | virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; | ||
| 66 | |||
| 67 | Service::APT::AppletId id; ///< Id of this Applet | ||
| 68 | std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet | ||
| 69 | |||
| 70 | /// Whether this applet is currently running instead of the host application or not. | ||
| 71 | bool is_running = false; | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// Returns whether a library applet is currently running | ||
| 75 | bool IsLibraryAppletRunning(); | ||
| 76 | |||
| 77 | /// Initializes the HLE applets | ||
| 78 | void Init(); | ||
| 79 | |||
| 80 | /// Shuts down the HLE applets | ||
| 81 | void Shutdown(); | ||
| 82 | } | ||
| 83 | } // namespace | ||
diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp deleted file mode 100644 index 518f371f5..000000000 --- a/src/core/hle/applets/erreula.cpp +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/string_util.h" | ||
| 6 | #include "core/hle/applets/erreula.h" | ||
| 7 | #include "core/hle/service/apt/apt.h" | ||
| 8 | |||
| 9 | namespace HLE { | ||
| 10 | namespace Applets { | ||
| 11 | |||
| 12 | ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||
| 13 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { | ||
| 14 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||
| 15 | UNIMPLEMENTED(); | ||
| 16 | // TODO(Subv): Find the right error code | ||
| 17 | return ResultCode(-1); | ||
| 18 | } | ||
| 19 | |||
| 20 | // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared | ||
| 21 | // memory. | ||
| 22 | // Create the SharedMemory that will hold the framebuffer data | ||
| 23 | Service::APT::CaptureBufferInfo capture_info; | ||
| 24 | ASSERT(sizeof(capture_info) == parameter.buffer.size()); | ||
| 25 | |||
| 26 | memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); | ||
| 27 | |||
| 28 | // TODO: allocated memory never released | ||
| 29 | using Kernel::MemoryPermission; | ||
| 30 | // Allocate a heap block of the required size for this applet. | ||
| 31 | heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); | ||
| 32 | // Create a SharedMemory that directly points to this heap block. | ||
| 33 | framebuffer_memory = Kernel::SharedMemory::CreateForApplet( | ||
| 34 | heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, | ||
| 35 | "ErrEula Memory"); | ||
| 36 | |||
| 37 | // Send the response message with the newly created SharedMemory | ||
| 38 | Service::APT::MessageParameter result; | ||
| 39 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); | ||
| 40 | result.buffer.clear(); | ||
| 41 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 42 | result.sender_id = static_cast<u32>(id); | ||
| 43 | result.object = framebuffer_memory; | ||
| 44 | |||
| 45 | Service::APT::SendParameter(result); | ||
| 46 | return RESULT_SUCCESS; | ||
| 47 | } | ||
| 48 | |||
| 49 | ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) { | ||
| 50 | is_running = true; | ||
| 51 | |||
| 52 | // TODO(Subv): Set the expected fields in the response buffer before resending it to the | ||
| 53 | // application. | ||
| 54 | // TODO(Subv): Reverse the parameter format for the ErrEula applet | ||
| 55 | |||
| 56 | // Let the application know that we're closing | ||
| 57 | Service::APT::MessageParameter message; | ||
| 58 | message.buffer.resize(parameter.buffer.size()); | ||
| 59 | std::fill(message.buffer.begin(), message.buffer.end(), 0); | ||
| 60 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); | ||
| 61 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 62 | message.sender_id = static_cast<u32>(id); | ||
| 63 | Service::APT::SendParameter(message); | ||
| 64 | |||
| 65 | is_running = false; | ||
| 66 | return RESULT_SUCCESS; | ||
| 67 | } | ||
| 68 | |||
| 69 | void ErrEula::Update() {} | ||
| 70 | |||
| 71 | } // namespace Applets | ||
| 72 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h deleted file mode 100644 index 681bbea0c..000000000 --- a/src/core/hle/applets/erreula.h +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/applets/applet.h" | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | ||
| 9 | |||
| 10 | namespace HLE { | ||
| 11 | namespace Applets { | ||
| 12 | |||
| 13 | class ErrEula final : public Applet { | ||
| 14 | public: | ||
| 15 | explicit ErrEula(Service::APT::AppletId id) : Applet(id) {} | ||
| 16 | |||
| 17 | ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||
| 18 | ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||
| 19 | void Update() override; | ||
| 20 | |||
| 21 | private: | ||
| 22 | /// This SharedMemory will be created when we receive the LibAppJustStarted message. | ||
| 23 | /// It holds the framebuffer info retrieved by the application with | ||
| 24 | /// GSPGPU::ImportDisplayCaptureInfo | ||
| 25 | Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Applets | ||
| 29 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp deleted file mode 100644 index f225c23a5..000000000 --- a/src/core/hle/applets/mii_selector.cpp +++ /dev/null | |||
| @@ -1,86 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <string> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | #include "core/hle/applets/mii_selector.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/shared_memory.h" | ||
| 13 | #include "core/hle/result.h" | ||
| 14 | |||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 16 | |||
| 17 | namespace HLE { | ||
| 18 | namespace Applets { | ||
| 19 | |||
| 20 | ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||
| 21 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { | ||
| 22 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||
| 23 | UNIMPLEMENTED(); | ||
| 24 | // TODO(Subv): Find the right error code | ||
| 25 | return ResultCode(-1); | ||
| 26 | } | ||
| 27 | |||
| 28 | // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared | ||
| 29 | // memory. | ||
| 30 | // Create the SharedMemory that will hold the framebuffer data | ||
| 31 | Service::APT::CaptureBufferInfo capture_info; | ||
| 32 | ASSERT(sizeof(capture_info) == parameter.buffer.size()); | ||
| 33 | |||
| 34 | memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); | ||
| 35 | |||
| 36 | using Kernel::MemoryPermission; | ||
| 37 | // Allocate a heap block of the required size for this applet. | ||
| 38 | heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); | ||
| 39 | // Create a SharedMemory that directly points to this heap block. | ||
| 40 | framebuffer_memory = Kernel::SharedMemory::CreateForApplet( | ||
| 41 | heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, | ||
| 42 | "MiiSelector Memory"); | ||
| 43 | |||
| 44 | // Send the response message with the newly created SharedMemory | ||
| 45 | Service::APT::MessageParameter result; | ||
| 46 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); | ||
| 47 | result.buffer.clear(); | ||
| 48 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 49 | result.sender_id = static_cast<u32>(id); | ||
| 50 | result.object = framebuffer_memory; | ||
| 51 | |||
| 52 | Service::APT::SendParameter(result); | ||
| 53 | return RESULT_SUCCESS; | ||
| 54 | } | ||
| 55 | |||
| 56 | ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) { | ||
| 57 | is_running = true; | ||
| 58 | |||
| 59 | // TODO(Subv): Set the expected fields in the response buffer before resending it to the | ||
| 60 | // application. | ||
| 61 | // TODO(Subv): Reverse the parameter format for the Mii Selector | ||
| 62 | |||
| 63 | memcpy(&config, parameter.buffer.data(), parameter.buffer.size()); | ||
| 64 | |||
| 65 | // TODO(Subv): Find more about this structure, result code 0 is enough to let most games | ||
| 66 | // continue. | ||
| 67 | MiiResult result; | ||
| 68 | memset(&result, 0, sizeof(result)); | ||
| 69 | result.return_code = 0; | ||
| 70 | |||
| 71 | // Let the application know that we're closing | ||
| 72 | Service::APT::MessageParameter message; | ||
| 73 | message.buffer.resize(sizeof(MiiResult)); | ||
| 74 | std::memcpy(message.buffer.data(), &result, message.buffer.size()); | ||
| 75 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); | ||
| 76 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 77 | message.sender_id = static_cast<u32>(id); | ||
| 78 | Service::APT::SendParameter(message); | ||
| 79 | |||
| 80 | is_running = false; | ||
| 81 | return RESULT_SUCCESS; | ||
| 82 | } | ||
| 83 | |||
| 84 | void MiiSelector::Update() {} | ||
| 85 | } // namespace Applets | ||
| 86 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h deleted file mode 100644 index 136ce8948..000000000 --- a/src/core/hle/applets/mii_selector.h +++ /dev/null | |||
| @@ -1,78 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/applets/applet.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/shared_memory.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/hle/service/apt/apt.h" | ||
| 14 | |||
| 15 | namespace HLE { | ||
| 16 | namespace Applets { | ||
| 17 | |||
| 18 | struct MiiConfig { | ||
| 19 | u8 enable_cancel_button; | ||
| 20 | u8 enable_guest_mii; | ||
| 21 | u8 show_on_top_screen; | ||
| 22 | INSERT_PADDING_BYTES(5); | ||
| 23 | u16 title[0x40]; | ||
| 24 | INSERT_PADDING_BYTES(4); | ||
| 25 | u8 show_guest_miis; | ||
| 26 | INSERT_PADDING_BYTES(3); | ||
| 27 | u32 initially_selected_mii_index; | ||
| 28 | u8 guest_mii_whitelist[6]; | ||
| 29 | u8 user_mii_whitelist[0x64]; | ||
| 30 | INSERT_PADDING_BYTES(2); | ||
| 31 | u32 magic_value; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(MiiConfig) == 0x104, "MiiConfig structure has incorrect size"); | ||
| 34 | #define ASSERT_REG_POSITION(field_name, position) \ | ||
| 35 | static_assert(offsetof(MiiConfig, field_name) == position, \ | ||
| 36 | "Field " #field_name " has invalid position") | ||
| 37 | ASSERT_REG_POSITION(title, 0x08); | ||
| 38 | ASSERT_REG_POSITION(show_guest_miis, 0x8C); | ||
| 39 | ASSERT_REG_POSITION(initially_selected_mii_index, 0x90); | ||
| 40 | ASSERT_REG_POSITION(guest_mii_whitelist, 0x94); | ||
| 41 | #undef ASSERT_REG_POSITION | ||
| 42 | |||
| 43 | struct MiiResult { | ||
| 44 | u32 return_code; | ||
| 45 | u32 is_guest_mii_selected; | ||
| 46 | u32 selected_guest_mii_index; | ||
| 47 | // TODO(mailwl): expand to Mii Format structure: https://www.3dbrew.org/wiki/Mii | ||
| 48 | u8 selected_mii_data[0x5C]; | ||
| 49 | INSERT_PADDING_BYTES(2); | ||
| 50 | u16 mii_data_checksum; | ||
| 51 | u16 guest_mii_name[0xC]; | ||
| 52 | }; | ||
| 53 | static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); | ||
| 54 | #define ASSERT_REG_POSITION(field_name, position) \ | ||
| 55 | static_assert(offsetof(MiiResult, field_name) == position, \ | ||
| 56 | "Field " #field_name " has invalid position") | ||
| 57 | ASSERT_REG_POSITION(selected_mii_data, 0x0C); | ||
| 58 | ASSERT_REG_POSITION(guest_mii_name, 0x6C); | ||
| 59 | #undef ASSERT_REG_POSITION | ||
| 60 | |||
| 61 | class MiiSelector final : public Applet { | ||
| 62 | public: | ||
| 63 | MiiSelector(Service::APT::AppletId id) : Applet(id) {} | ||
| 64 | |||
| 65 | ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||
| 66 | ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||
| 67 | void Update() override; | ||
| 68 | |||
| 69 | private: | ||
| 70 | /// This SharedMemory will be created when we receive the LibAppJustStarted message. | ||
| 71 | /// It holds the framebuffer info retrieved by the application with | ||
| 72 | /// GSPGPU::ImportDisplayCaptureInfo | ||
| 73 | Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||
| 74 | |||
| 75 | MiiConfig config; | ||
| 76 | }; | ||
| 77 | } // namespace Applets | ||
| 78 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp deleted file mode 100644 index 50d79190b..000000000 --- a/src/core/hle/applets/mint.cpp +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/string_util.h" | ||
| 6 | #include "core/hle/applets/mint.h" | ||
| 7 | #include "core/hle/service/apt/apt.h" | ||
| 8 | |||
| 9 | namespace HLE { | ||
| 10 | namespace Applets { | ||
| 11 | |||
| 12 | ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { | ||
| 13 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { | ||
| 14 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||
| 15 | UNIMPLEMENTED(); | ||
| 16 | // TODO(Subv): Find the right error code | ||
| 17 | return ResultCode(-1); | ||
| 18 | } | ||
| 19 | |||
| 20 | // The Request message contains a buffer with the size of the framebuffer shared | ||
| 21 | // memory. | ||
| 22 | // Create the SharedMemory that will hold the framebuffer data | ||
| 23 | Service::APT::CaptureBufferInfo capture_info; | ||
| 24 | ASSERT(sizeof(capture_info) == parameter.buffer.size()); | ||
| 25 | |||
| 26 | memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); | ||
| 27 | |||
| 28 | // TODO: allocated memory never released | ||
| 29 | using Kernel::MemoryPermission; | ||
| 30 | // Allocate a heap block of the required size for this applet. | ||
| 31 | heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); | ||
| 32 | // Create a SharedMemory that directly points to this heap block. | ||
| 33 | framebuffer_memory = Kernel::SharedMemory::CreateForApplet( | ||
| 34 | heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, | ||
| 35 | "Mint Memory"); | ||
| 36 | |||
| 37 | // Send the response message with the newly created SharedMemory | ||
| 38 | Service::APT::MessageParameter result; | ||
| 39 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); | ||
| 40 | result.buffer.clear(); | ||
| 41 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 42 | result.sender_id = static_cast<u32>(id); | ||
| 43 | result.object = framebuffer_memory; | ||
| 44 | |||
| 45 | Service::APT::SendParameter(result); | ||
| 46 | return RESULT_SUCCESS; | ||
| 47 | } | ||
| 48 | |||
| 49 | ResultCode Mint::StartImpl(const Service::APT::AppletStartupParameter& parameter) { | ||
| 50 | is_running = true; | ||
| 51 | |||
| 52 | // TODO(Subv): Set the expected fields in the response buffer before resending it to the | ||
| 53 | // application. | ||
| 54 | // TODO(Subv): Reverse the parameter format for the Mint applet | ||
| 55 | |||
| 56 | // Let the application know that we're closing | ||
| 57 | Service::APT::MessageParameter message; | ||
| 58 | message.buffer.resize(parameter.buffer.size()); | ||
| 59 | std::fill(message.buffer.begin(), message.buffer.end(), 0); | ||
| 60 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); | ||
| 61 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 62 | message.sender_id = static_cast<u32>(id); | ||
| 63 | Service::APT::SendParameter(message); | ||
| 64 | |||
| 65 | is_running = false; | ||
| 66 | return RESULT_SUCCESS; | ||
| 67 | } | ||
| 68 | |||
| 69 | void Mint::Update() {} | ||
| 70 | |||
| 71 | } // namespace Applets | ||
| 72 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/mint.h b/src/core/hle/applets/mint.h deleted file mode 100644 index d23dc40f9..000000000 --- a/src/core/hle/applets/mint.h +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/applets/applet.h" | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | ||
| 9 | |||
| 10 | namespace HLE { | ||
| 11 | namespace Applets { | ||
| 12 | |||
| 13 | class Mint final : public Applet { | ||
| 14 | public: | ||
| 15 | explicit Mint(Service::APT::AppletId id) : Applet(id) {} | ||
| 16 | |||
| 17 | ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||
| 18 | ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||
| 19 | void Update() override; | ||
| 20 | |||
| 21 | private: | ||
| 22 | /// This SharedMemory will be created when we receive the Request message. | ||
| 23 | /// It holds the framebuffer info retrieved by the application with | ||
| 24 | /// GSPGPU::ImportDisplayCaptureInfo | ||
| 25 | Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Applets | ||
| 29 | } // namespace HLE | ||
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp deleted file mode 100644 index 0bc471a3a..000000000 --- a/src/core/hle/applets/swkbd.cpp +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <string> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | #include "core/hle/applets/swkbd.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/shared_memory.h" | ||
| 13 | #include "core/hle/result.h" | ||
| 14 | #include "core/hle/service/gsp_gpu.h" | ||
| 15 | #include "core/hle/service/hid/hid.h" | ||
| 16 | #include "core/memory.h" | ||
| 17 | |||
| 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 19 | |||
| 20 | namespace HLE { | ||
| 21 | namespace Applets { | ||
| 22 | |||
| 23 | ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { | ||
| 24 | if (parameter.signal != static_cast<u32>(Service::APT::SignalType::Request)) { | ||
| 25 | LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); | ||
| 26 | UNIMPLEMENTED(); | ||
| 27 | // TODO(Subv): Find the right error code | ||
| 28 | return ResultCode(-1); | ||
| 29 | } | ||
| 30 | |||
| 31 | // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared | ||
| 32 | // memory. | ||
| 33 | // Create the SharedMemory that will hold the framebuffer data | ||
| 34 | Service::APT::CaptureBufferInfo capture_info; | ||
| 35 | ASSERT(sizeof(capture_info) == parameter.buffer.size()); | ||
| 36 | |||
| 37 | memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); | ||
| 38 | |||
| 39 | using Kernel::MemoryPermission; | ||
| 40 | // Allocate a heap block of the required size for this applet. | ||
| 41 | heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); | ||
| 42 | // Create a SharedMemory that directly points to this heap block. | ||
| 43 | framebuffer_memory = Kernel::SharedMemory::CreateForApplet( | ||
| 44 | heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, | ||
| 45 | "SoftwareKeyboard Memory"); | ||
| 46 | |||
| 47 | // Send the response message with the newly created SharedMemory | ||
| 48 | Service::APT::MessageParameter result; | ||
| 49 | result.signal = static_cast<u32>(Service::APT::SignalType::Response); | ||
| 50 | result.buffer.clear(); | ||
| 51 | result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 52 | result.sender_id = static_cast<u32>(id); | ||
| 53 | result.object = framebuffer_memory; | ||
| 54 | |||
| 55 | Service::APT::SendParameter(result); | ||
| 56 | return RESULT_SUCCESS; | ||
| 57 | } | ||
| 58 | |||
| 59 | ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { | ||
| 60 | ASSERT_MSG(parameter.buffer.size() == sizeof(config), | ||
| 61 | "The size of the parameter (SoftwareKeyboardConfig) is wrong"); | ||
| 62 | |||
| 63 | memcpy(&config, parameter.buffer.data(), parameter.buffer.size()); | ||
| 64 | text_memory = | ||
| 65 | boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); | ||
| 66 | |||
| 67 | // TODO(Subv): Verify if this is the correct behavior | ||
| 68 | memset(text_memory->GetPointer(), 0, text_memory->size); | ||
| 69 | |||
| 70 | DrawScreenKeyboard(); | ||
| 71 | |||
| 72 | is_running = true; | ||
| 73 | return RESULT_SUCCESS; | ||
| 74 | } | ||
| 75 | |||
| 76 | void SoftwareKeyboard::Update() { | ||
| 77 | // TODO(Subv): Handle input using the touch events from the HID module | ||
| 78 | |||
| 79 | // TODO(Subv): Remove this hardcoded text | ||
| 80 | std::u16string text = Common::UTF8ToUTF16("Citra"); | ||
| 81 | memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t)); | ||
| 82 | |||
| 83 | // TODO(Subv): Ask for input and write it to the shared memory | ||
| 84 | // TODO(Subv): Find out what are the possible values for the return code, | ||
| 85 | // some games seem to check for a hardcoded 2 | ||
| 86 | config.return_code = 2; | ||
| 87 | config.text_length = 6; | ||
| 88 | config.text_offset = 0; | ||
| 89 | |||
| 90 | // TODO(Subv): We're finalizing the applet immediately after it's started, | ||
| 91 | // but we should defer this call until after all the input has been collected. | ||
| 92 | Finalize(); | ||
| 93 | } | ||
| 94 | |||
| 95 | void SoftwareKeyboard::DrawScreenKeyboard() { | ||
| 96 | auto bottom_screen = Service::GSP::GetFrameBufferInfo(0, 1); | ||
| 97 | auto info = bottom_screen->framebuffer_info[bottom_screen->index]; | ||
| 98 | |||
| 99 | // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer | ||
| 100 | Memory::ZeroBlock(info.address_left, info.stride * 320); | ||
| 101 | |||
| 102 | Service::GSP::SetBufferSwap(1, info); | ||
| 103 | } | ||
| 104 | |||
| 105 | void SoftwareKeyboard::Finalize() { | ||
| 106 | // Let the application know that we're closing | ||
| 107 | Service::APT::MessageParameter message; | ||
| 108 | message.buffer.resize(sizeof(SoftwareKeyboardConfig)); | ||
| 109 | std::memcpy(message.buffer.data(), &config, message.buffer.size()); | ||
| 110 | message.signal = static_cast<u32>(Service::APT::SignalType::WakeupByExit); | ||
| 111 | message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); | ||
| 112 | message.sender_id = static_cast<u32>(id); | ||
| 113 | Service::APT::SendParameter(message); | ||
| 114 | |||
| 115 | is_running = false; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } // namespace | ||
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h deleted file mode 100644 index cc92a8f19..000000000 --- a/src/core/hle/applets/swkbd.h +++ /dev/null | |||
| @@ -1,85 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/applets/applet.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/shared_memory.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/hle/service/apt/apt.h" | ||
| 14 | |||
| 15 | namespace HLE { | ||
| 16 | namespace Applets { | ||
| 17 | |||
| 18 | struct SoftwareKeyboardConfig { | ||
| 19 | INSERT_PADDING_WORDS(0x8); | ||
| 20 | |||
| 21 | u16 max_text_length; ///< Maximum length of the input text | ||
| 22 | |||
| 23 | INSERT_PADDING_BYTES(0x6E); | ||
| 24 | |||
| 25 | char16_t display_text[65]; ///< Text to display when asking the user for input | ||
| 26 | |||
| 27 | INSERT_PADDING_BYTES(0xE); | ||
| 28 | |||
| 29 | u32 default_text_offset; ///< Offset of the default text in the output SharedMemory | ||
| 30 | |||
| 31 | INSERT_PADDING_WORDS(0x3); | ||
| 32 | |||
| 33 | u32 shared_memory_size; ///< Size of the SharedMemory | ||
| 34 | |||
| 35 | INSERT_PADDING_WORDS(0x1); | ||
| 36 | |||
| 37 | u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown | ||
| 38 | |||
| 39 | INSERT_PADDING_WORDS(0x2); | ||
| 40 | |||
| 41 | u32 text_offset; ///< Offset in the SharedMemory where the output text starts | ||
| 42 | u16 text_length; ///< Length in characters of the output text | ||
| 43 | |||
| 44 | INSERT_PADDING_BYTES(0x2B6); | ||
| 45 | }; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * The size of this structure (0x400) has been verified via reverse engineering of multiple games | ||
| 49 | * that use the software keyboard. | ||
| 50 | */ | ||
| 51 | static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); | ||
| 52 | |||
| 53 | class SoftwareKeyboard final : public Applet { | ||
| 54 | public: | ||
| 55 | SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {} | ||
| 56 | |||
| 57 | ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; | ||
| 58 | ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; | ||
| 59 | void Update() override; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Draws a keyboard to the current bottom screen framebuffer. | ||
| 63 | */ | ||
| 64 | void DrawScreenKeyboard(); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Sends the LibAppletClosing signal to the application, | ||
| 68 | * along with the relevant data buffers. | ||
| 69 | */ | ||
| 70 | void Finalize(); | ||
| 71 | |||
| 72 | private: | ||
| 73 | /// This SharedMemory will be created when we receive the LibAppJustStarted message. | ||
| 74 | /// It holds the framebuffer info retrieved by the application with | ||
| 75 | /// GSPGPU::ImportDisplayCaptureInfo | ||
| 76 | Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; | ||
| 77 | |||
| 78 | /// SharedMemory where the output text will be stored | ||
| 79 | Kernel::SharedPtr<Kernel::SharedMemory> text_memory; | ||
| 80 | |||
| 81 | /// Configuration of this instance of the SoftwareKeyboard, as received from the application | ||
| 82 | SoftwareKeyboardConfig config; | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | } // namespace | ||
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp deleted file mode 100644 index e3dd23949..000000000 --- a/src/core/hle/service/ac/ac.cpp +++ /dev/null | |||
| @@ -1,186 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/ipc.h" | ||
| 10 | #include "core/hle/kernel/event.h" | ||
| 11 | #include "core/hle/kernel/handle_table.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/hle/service/ac/ac.h" | ||
| 14 | #include "core/hle/service/ac/ac_i.h" | ||
| 15 | #include "core/hle/service/ac/ac_u.h" | ||
| 16 | #include "core/memory.h" | ||
| 17 | |||
| 18 | namespace Service { | ||
| 19 | namespace AC { | ||
| 20 | |||
| 21 | struct ACConfig { | ||
| 22 | std::array<u8, 0x200> data; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static ACConfig default_config{}; | ||
| 26 | |||
| 27 | static bool ac_connected = false; | ||
| 28 | |||
| 29 | static Kernel::SharedPtr<Kernel::Event> close_event; | ||
| 30 | static Kernel::SharedPtr<Kernel::Event> connect_event; | ||
| 31 | static Kernel::SharedPtr<Kernel::Event> disconnect_event; | ||
| 32 | |||
| 33 | void CreateDefaultConfig(Interface* self) { | ||
| 34 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 35 | |||
| 36 | u32 ac_config_addr = cmd_buff[65]; | ||
| 37 | |||
| 38 | ASSERT_MSG(cmd_buff[64] == (sizeof(ACConfig) << 14 | 2), | ||
| 39 | "Output buffer size not equal ACConfig size"); | ||
| 40 | |||
| 41 | Memory::WriteBlock(ac_config_addr, &default_config, sizeof(ACConfig)); | ||
| 42 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 43 | |||
| 44 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 45 | } | ||
| 46 | |||
| 47 | void ConnectAsync(Interface* self) { | ||
| 48 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 49 | |||
| 50 | connect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); | ||
| 51 | if (connect_event) { | ||
| 52 | connect_event->name = "AC:connect_event"; | ||
| 53 | connect_event->Signal(); | ||
| 54 | ac_connected = true; | ||
| 55 | } | ||
| 56 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 57 | |||
| 58 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 59 | } | ||
| 60 | |||
| 61 | void GetConnectResult(Interface* self) { | ||
| 62 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 63 | |||
| 64 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 65 | |||
| 66 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 67 | } | ||
| 68 | |||
| 69 | void CloseAsync(Interface* self) { | ||
| 70 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 71 | |||
| 72 | if (ac_connected && disconnect_event) { | ||
| 73 | disconnect_event->Signal(); | ||
| 74 | } | ||
| 75 | |||
| 76 | close_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); | ||
| 77 | if (close_event) { | ||
| 78 | close_event->name = "AC:close_event"; | ||
| 79 | close_event->Signal(); | ||
| 80 | } | ||
| 81 | |||
| 82 | ac_connected = false; | ||
| 83 | |||
| 84 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 85 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 86 | } | ||
| 87 | |||
| 88 | void GetCloseResult(Interface* self) { | ||
| 89 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 90 | |||
| 91 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 92 | |||
| 93 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 94 | } | ||
| 95 | |||
| 96 | void GetWifiStatus(Interface* self) { | ||
| 97 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 98 | |||
| 99 | // TODO(purpasmart96): This function is only a stub, | ||
| 100 | // it returns a valid result without implementing full functionality. | ||
| 101 | |||
| 102 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 103 | cmd_buff[2] = 0; // Connection type set to none | ||
| 104 | |||
| 105 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 106 | } | ||
| 107 | |||
| 108 | void GetInfraPriority(Interface* self) { | ||
| 109 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 110 | |||
| 111 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 112 | cmd_buff[2] = 0; // Infra Priority, default 0 | ||
| 113 | |||
| 114 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 115 | } | ||
| 116 | |||
| 117 | void SetRequestEulaVersion(Interface* self) { | ||
| 118 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 119 | |||
| 120 | u32 major = cmd_buff[1] & 0xFF; | ||
| 121 | u32 minor = cmd_buff[2] & 0xFF; | ||
| 122 | |||
| 123 | ASSERT_MSG(cmd_buff[3] == (sizeof(ACConfig) << 14 | 2), | ||
| 124 | "Input buffer size not equal ACConfig size"); | ||
| 125 | ASSERT_MSG(cmd_buff[64] == (sizeof(ACConfig) << 14 | 2), | ||
| 126 | "Output buffer size not equal ACConfig size"); | ||
| 127 | |||
| 128 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 129 | cmd_buff[2] = 0; // Infra Priority | ||
| 130 | |||
| 131 | LOG_WARNING(Service_AC, "(STUBBED) called, major=%u, minor=%u", major, minor); | ||
| 132 | } | ||
| 133 | |||
| 134 | void RegisterDisconnectEvent(Interface* self) { | ||
| 135 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 136 | |||
| 137 | disconnect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); | ||
| 138 | if (disconnect_event) { | ||
| 139 | disconnect_event->name = "AC:disconnect_event"; | ||
| 140 | } | ||
| 141 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 142 | |||
| 143 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 144 | } | ||
| 145 | |||
| 146 | void IsConnected(Interface* self) { | ||
| 147 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 148 | |||
| 149 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 150 | cmd_buff[2] = ac_connected; | ||
| 151 | |||
| 152 | LOG_WARNING(Service_AC, "(STUBBED) called"); | ||
| 153 | } | ||
| 154 | |||
| 155 | void SetClientVersion(Interface* self) { | ||
| 156 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 157 | |||
| 158 | const u32 version = cmd_buff[1]; | ||
| 159 | self->SetVersion(version); | ||
| 160 | |||
| 161 | LOG_WARNING(Service_AC, "(STUBBED) called, version: 0x%08X", version); | ||
| 162 | |||
| 163 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 164 | } | ||
| 165 | |||
| 166 | void Init() { | ||
| 167 | AddService(new AC_I); | ||
| 168 | AddService(new AC_U); | ||
| 169 | |||
| 170 | ac_connected = false; | ||
| 171 | |||
| 172 | close_event = nullptr; | ||
| 173 | connect_event = nullptr; | ||
| 174 | disconnect_event = nullptr; | ||
| 175 | } | ||
| 176 | |||
| 177 | void Shutdown() { | ||
| 178 | ac_connected = false; | ||
| 179 | |||
| 180 | close_event = nullptr; | ||
| 181 | connect_event = nullptr; | ||
| 182 | disconnect_event = nullptr; | ||
| 183 | } | ||
| 184 | |||
| 185 | } // namespace AC | ||
| 186 | } // namespace Service | ||
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h deleted file mode 100644 index 6185faf9b..000000000 --- a/src/core/hle/service/ac/ac.h +++ /dev/null | |||
| @@ -1,134 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | class Interface; | ||
| 10 | |||
| 11 | namespace AC { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * AC::CreateDefaultConfig service function | ||
| 15 | * Inputs: | ||
| 16 | * 64 : ACConfig size << 14 | 2 | ||
| 17 | * 65 : pointer to ACConfig struct | ||
| 18 | * Outputs: | ||
| 19 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 20 | */ | ||
| 21 | void CreateDefaultConfig(Interface* self); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * AC::ConnectAsync service function | ||
| 25 | * Inputs: | ||
| 26 | * 1 : ProcessId Header | ||
| 27 | * 3 : Copy Handle Header | ||
| 28 | * 4 : Connection Event handle | ||
| 29 | * 5 : ACConfig size << 14 | 2 | ||
| 30 | * 6 : pointer to ACConfig struct | ||
| 31 | * Outputs: | ||
| 32 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 33 | */ | ||
| 34 | void ConnectAsync(Interface* self); | ||
| 35 | |||
| 36 | /** | ||
| 37 | * AC::GetConnectResult service function | ||
| 38 | * Inputs: | ||
| 39 | * 1 : ProcessId Header | ||
| 40 | * Outputs: | ||
| 41 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 42 | */ | ||
| 43 | void GetConnectResult(Interface* self); | ||
| 44 | |||
| 45 | /** | ||
| 46 | * AC::CloseAsync service function | ||
| 47 | * Inputs: | ||
| 48 | * 1 : ProcessId Header | ||
| 49 | * 3 : Copy Handle Header | ||
| 50 | * 4 : Event handle, should be signaled when AC connection is closed | ||
| 51 | * Outputs: | ||
| 52 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 53 | */ | ||
| 54 | void CloseAsync(Interface* self); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * AC::GetCloseResult service function | ||
| 58 | * Inputs: | ||
| 59 | * 1 : ProcessId Header | ||
| 60 | * Outputs: | ||
| 61 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 62 | */ | ||
| 63 | void GetCloseResult(Interface* self); | ||
| 64 | |||
| 65 | /** | ||
| 66 | * AC::GetWifiStatus service function | ||
| 67 | * Outputs: | ||
| 68 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 69 | * 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet. | ||
| 70 | */ | ||
| 71 | void GetWifiStatus(Interface* self); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * AC::GetInfraPriority service function | ||
| 75 | * Inputs: | ||
| 76 | * 1 : ACConfig size << 14 | 2 | ||
| 77 | * 2 : pointer to ACConfig struct | ||
| 78 | * Outputs: | ||
| 79 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 80 | * 2 : Infra Priority | ||
| 81 | */ | ||
| 82 | void GetInfraPriority(Interface* self); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * AC::SetRequestEulaVersion service function | ||
| 86 | * Inputs: | ||
| 87 | * 1 : Eula Version major | ||
| 88 | * 2 : Eula Version minor | ||
| 89 | * 3 : ACConfig size << 14 | 2 | ||
| 90 | * 4 : Input pointer to ACConfig struct | ||
| 91 | * 64 : ACConfig size << 14 | 2 | ||
| 92 | * 65 : Output pointer to ACConfig struct | ||
| 93 | * Outputs: | ||
| 94 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 95 | * 2 : Infra Priority | ||
| 96 | */ | ||
| 97 | void SetRequestEulaVersion(Interface* self); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * AC::RegisterDisconnectEvent service function | ||
| 101 | * Inputs: | ||
| 102 | * 1 : ProcessId Header | ||
| 103 | * 3 : Copy Handle Header | ||
| 104 | * 4 : Event handle, should be signaled when AC connection is closed | ||
| 105 | * Outputs: | ||
| 106 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 107 | */ | ||
| 108 | void RegisterDisconnectEvent(Interface* self); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * AC::IsConnected service function | ||
| 112 | * Outputs: | ||
| 113 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 114 | * 2 : bool, is connected | ||
| 115 | */ | ||
| 116 | void IsConnected(Interface* self); | ||
| 117 | |||
| 118 | /** | ||
| 119 | * AC::SetClientVersion service function | ||
| 120 | * Inputs: | ||
| 121 | * 1 : Used SDK Version | ||
| 122 | * Outputs: | ||
| 123 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 124 | */ | ||
| 125 | void SetClientVersion(Interface* self); | ||
| 126 | |||
| 127 | /// Initialize AC service | ||
| 128 | void Init(); | ||
| 129 | |||
| 130 | /// Shutdown AC service | ||
| 131 | void Shutdown(); | ||
| 132 | |||
| 133 | } // namespace AC | ||
| 134 | } // namespace Service | ||
diff --git a/src/core/hle/service/ac/ac_i.cpp b/src/core/hle/service/ac/ac_i.cpp deleted file mode 100644 index b22fe3698..000000000 --- a/src/core/hle/service/ac/ac_i.cpp +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ac/ac.h" | ||
| 6 | #include "core/hle/service/ac/ac_i.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AC { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010000, CreateDefaultConfig, "CreateDefaultConfig"}, | ||
| 13 | {0x00040006, ConnectAsync, "ConnectAsync"}, | ||
| 14 | {0x00050002, GetConnectResult, "GetConnectResult"}, | ||
| 15 | {0x00070002, nullptr, "CancelConnectAsync"}, | ||
| 16 | {0x00080004, CloseAsync, "CloseAsync"}, | ||
| 17 | {0x00090002, GetCloseResult, "GetCloseResult"}, | ||
| 18 | {0x000A0000, nullptr, "GetLastErrorCode"}, | ||
| 19 | {0x000C0000, nullptr, "GetStatus"}, | ||
| 20 | {0x000D0000, GetWifiStatus, "GetWifiStatus"}, | ||
| 21 | {0x000E0042, nullptr, "GetCurrentAPInfo"}, | ||
| 22 | {0x00100042, nullptr, "GetCurrentNZoneInfo"}, | ||
| 23 | {0x00110042, nullptr, "GetNZoneApNumService"}, | ||
| 24 | {0x001D0042, nullptr, "ScanAPs"}, | ||
| 25 | {0x00240042, nullptr, "AddDenyApType"}, | ||
| 26 | {0x00270002, GetInfraPriority, "GetInfraPriority"}, | ||
| 27 | {0x002D0082, SetRequestEulaVersion, "SetRequestEulaVersion"}, | ||
| 28 | {0x00300004, RegisterDisconnectEvent, "RegisterDisconnectEvent"}, | ||
| 29 | {0x003C0042, nullptr, "GetAPSSIDList"}, | ||
| 30 | {0x003E0042, IsConnected, "IsConnected"}, | ||
| 31 | {0x00400042, SetClientVersion, "SetClientVersion"}, | ||
| 32 | }; | ||
| 33 | |||
| 34 | AC_I::AC_I() { | ||
| 35 | Register(FunctionTable); | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace AC | ||
| 39 | } // namespace Service | ||
diff --git a/src/core/hle/service/ac/ac_i.h b/src/core/hle/service/ac/ac_i.h deleted file mode 100644 index 465bba59c..000000000 --- a/src/core/hle/service/ac/ac_i.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AC { | ||
| 11 | |||
| 12 | class AC_I final : public Interface { | ||
| 13 | public: | ||
| 14 | AC_I(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ac:i"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AC | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ac/ac_u.cpp b/src/core/hle/service/ac/ac_u.cpp deleted file mode 100644 index 346671b4a..000000000 --- a/src/core/hle/service/ac/ac_u.cpp +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ac/ac.h" | ||
| 6 | #include "core/hle/service/ac/ac_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AC { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010000, CreateDefaultConfig, "CreateDefaultConfig"}, | ||
| 13 | {0x00040006, ConnectAsync, "ConnectAsync"}, | ||
| 14 | {0x00050002, GetConnectResult, "GetConnectResult"}, | ||
| 15 | {0x00070002, nullptr, "CancelConnectAsync"}, | ||
| 16 | {0x00080004, CloseAsync, "CloseAsync"}, | ||
| 17 | {0x00090002, GetCloseResult, "GetCloseResult"}, | ||
| 18 | {0x000A0000, nullptr, "GetLastErrorCode"}, | ||
| 19 | {0x000C0000, nullptr, "GetStatus"}, | ||
| 20 | {0x000D0000, GetWifiStatus, "GetWifiStatus"}, | ||
| 21 | {0x000E0042, nullptr, "GetCurrentAPInfo"}, | ||
| 22 | {0x00100042, nullptr, "GetCurrentNZoneInfo"}, | ||
| 23 | {0x00110042, nullptr, "GetNZoneApNumService"}, | ||
| 24 | {0x001D0042, nullptr, "ScanAPs"}, | ||
| 25 | {0x00240042, nullptr, "AddDenyApType"}, | ||
| 26 | {0x00270002, GetInfraPriority, "GetInfraPriority"}, | ||
| 27 | {0x002D0082, SetRequestEulaVersion, "SetRequestEulaVersion"}, | ||
| 28 | {0x00300004, RegisterDisconnectEvent, "RegisterDisconnectEvent"}, | ||
| 29 | {0x003C0042, nullptr, "GetAPSSIDList"}, | ||
| 30 | {0x003E0042, IsConnected, "IsConnected"}, | ||
| 31 | {0x00400042, SetClientVersion, "SetClientVersion"}, | ||
| 32 | }; | ||
| 33 | |||
| 34 | AC_U::AC_U() { | ||
| 35 | Register(FunctionTable); | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace AC | ||
| 39 | } // namespace Service | ||
diff --git a/src/core/hle/service/ac/ac_u.h b/src/core/hle/service/ac/ac_u.h deleted file mode 100644 index f9d21e112..000000000 --- a/src/core/hle/service/ac/ac_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AC { | ||
| 11 | |||
| 12 | class AC_U final : public Interface { | ||
| 13 | public: | ||
| 14 | AC_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ac:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AC | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act.cpp b/src/core/hle/service/act/act.cpp deleted file mode 100644 index 9600036c0..000000000 --- a/src/core/hle/service/act/act.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/act/act.h" | ||
| 6 | #include "core/hle/service/act/act_a.h" | ||
| 7 | #include "core/hle/service/act/act_u.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace ACT { | ||
| 11 | |||
| 12 | void Init() { | ||
| 13 | AddService(new ACT_A); | ||
| 14 | AddService(new ACT_U); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace ACT | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h deleted file mode 100644 index 1425291aa..000000000 --- a/src/core/hle/service/act/act.h +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace ACT { | ||
| 9 | |||
| 10 | /// Initializes all ACT services | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | } // namespace ACT | ||
| 14 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp deleted file mode 100644 index 5c523368f..000000000 --- a/src/core/hle/service/act/act_a.cpp +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/act/act.h" | ||
| 6 | #include "core/hle/service/act/act_a.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace ACT { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // act:u shared commands | ||
| 13 | {0x00010084, nullptr, "Initialize"}, | ||
| 14 | {0x00020040, nullptr, "GetErrorCode"}, | ||
| 15 | {0x000600C2, nullptr, "GetAccountDataBlock"}, | ||
| 16 | {0x000B0042, nullptr, "AcquireEulaList"}, | ||
| 17 | {0x000D0040, nullptr, "GenerateUuid"}, | ||
| 18 | // act:a | ||
| 19 | {0x041300C2, nullptr, "UpdateMiiImage"}, | ||
| 20 | {0x041B0142, nullptr, "AgreeEula"}, | ||
| 21 | {0x04210042, nullptr, "UploadMii"}, | ||
| 22 | {0x04230082, nullptr, "ValidateMailAddress"}, | ||
| 23 | }; | ||
| 24 | |||
| 25 | ACT_A::ACT_A() { | ||
| 26 | Register(FunctionTable); | ||
| 27 | } | ||
| 28 | |||
| 29 | } // namespace ACT | ||
| 30 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act_a.h b/src/core/hle/service/act/act_a.h deleted file mode 100644 index e3adb03e5..000000000 --- a/src/core/hle/service/act/act_a.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace ACT { | ||
| 11 | |||
| 12 | class ACT_A final : public Service::Interface { | ||
| 13 | public: | ||
| 14 | ACT_A(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "act:a"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace ACT | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act_u.cpp b/src/core/hle/service/act/act_u.cpp deleted file mode 100644 index cf98aa1d6..000000000 --- a/src/core/hle/service/act/act_u.cpp +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/act/act.h" | ||
| 6 | #include "core/hle/service/act/act_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace ACT { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // clang-format off | ||
| 13 | {0x00010084, nullptr, "Initialize"}, | ||
| 14 | {0x00020040, nullptr, "GetErrorCode"}, | ||
| 15 | {0x000600C2, nullptr, "GetAccountDataBlock"}, | ||
| 16 | {0x000B0042, nullptr, "AcquireEulaList"}, | ||
| 17 | {0x000D0040, nullptr, "GenerateUuid"}, | ||
| 18 | // clang-format on | ||
| 19 | }; | ||
| 20 | |||
| 21 | ACT_U::ACT_U() { | ||
| 22 | Register(FunctionTable); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // namespace ACT | ||
| 26 | } // namespace Service | ||
diff --git a/src/core/hle/service/act/act_u.h b/src/core/hle/service/act/act_u.h deleted file mode 100644 index 9d8538fbf..000000000 --- a/src/core/hle/service/act/act_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace ACT { | ||
| 11 | |||
| 12 | class ACT_U final : public Interface { | ||
| 13 | public: | ||
| 14 | ACT_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "act:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace ACT | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp deleted file mode 100644 index 961305e9f..000000000 --- a/src/core/hle/service/am/am.cpp +++ /dev/null | |||
| @@ -1,193 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cinttypes> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/ipc.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/am/am.h" | ||
| 12 | #include "core/hle/service/am/am_app.h" | ||
| 13 | #include "core/hle/service/am/am_net.h" | ||
| 14 | #include "core/hle/service/am/am_sys.h" | ||
| 15 | #include "core/hle/service/am/am_u.h" | ||
| 16 | #include "core/hle/service/service.h" | ||
| 17 | |||
| 18 | namespace Service { | ||
| 19 | namespace AM { | ||
| 20 | |||
| 21 | static std::array<u32, 3> am_content_count = {0, 0, 0}; | ||
| 22 | static std::array<u32, 3> am_titles_count = {0, 0, 0}; | ||
| 23 | static std::array<u32, 3> am_titles_list_count = {0, 0, 0}; | ||
| 24 | static u32 am_ticket_count = 0; | ||
| 25 | static u32 am_ticket_list_count = 0; | ||
| 26 | |||
| 27 | void GetNumPrograms(Service::Interface* self) { | ||
| 28 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 29 | |||
| 30 | u32 media_type = cmd_buff[1] & 0xFF; | ||
| 31 | |||
| 32 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 33 | cmd_buff[2] = am_titles_count[media_type]; | ||
| 34 | LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_count=0x%08x", media_type, | ||
| 35 | am_titles_count[media_type]); | ||
| 36 | } | ||
| 37 | |||
| 38 | void FindContentInfos(Service::Interface* self) { | ||
| 39 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 40 | |||
| 41 | u32 media_type = cmd_buff[1] & 0xFF; | ||
| 42 | u64 title_id = (static_cast<u64>(cmd_buff[3]) << 32) | cmd_buff[2]; | ||
| 43 | u32 content_ids_pointer = cmd_buff[6]; | ||
| 44 | u32 content_info_pointer = cmd_buff[8]; | ||
| 45 | |||
| 46 | am_content_count[media_type] = cmd_buff[4]; | ||
| 47 | |||
| 48 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 49 | LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016llx, content_cound=%u, " | ||
| 50 | "content_ids_pointer=0x%08x, content_info_pointer=0x%08x", | ||
| 51 | media_type, title_id, am_content_count[media_type], content_ids_pointer, | ||
| 52 | content_info_pointer); | ||
| 53 | } | ||
| 54 | |||
| 55 | void ListContentInfos(Service::Interface* self) { | ||
| 56 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 57 | |||
| 58 | u32 media_type = cmd_buff[2] & 0xFF; | ||
| 59 | u64 title_id = (static_cast<u64>(cmd_buff[4]) << 32) | cmd_buff[3]; | ||
| 60 | u32 start_index = cmd_buff[5]; | ||
| 61 | u32 content_info_pointer = cmd_buff[7]; | ||
| 62 | |||
| 63 | am_content_count[media_type] = cmd_buff[1]; | ||
| 64 | |||
| 65 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 66 | cmd_buff[2] = am_content_count[media_type]; | ||
| 67 | LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, content_count=%u, title_id=0x%016" PRIx64 | ||
| 68 | ", start_index=0x%08x, content_info_pointer=0x%08X", | ||
| 69 | media_type, am_content_count[media_type], title_id, start_index, | ||
| 70 | content_info_pointer); | ||
| 71 | } | ||
| 72 | |||
| 73 | void DeleteContents(Service::Interface* self) { | ||
| 74 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 75 | |||
| 76 | u32 media_type = cmd_buff[1] & 0xFF; | ||
| 77 | u64 title_id = (static_cast<u64>(cmd_buff[3]) << 32) | cmd_buff[2]; | ||
| 78 | u32 content_ids_pointer = cmd_buff[6]; | ||
| 79 | |||
| 80 | am_content_count[media_type] = cmd_buff[4]; | ||
| 81 | |||
| 82 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 83 | LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64 | ||
| 84 | ", content_count=%u, content_ids_pointer=0x%08x", | ||
| 85 | media_type, title_id, am_content_count[media_type], content_ids_pointer); | ||
| 86 | } | ||
| 87 | |||
| 88 | void GetProgramList(Service::Interface* self) { | ||
| 89 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 90 | |||
| 91 | u32 media_type = cmd_buff[2] & 0xFF; | ||
| 92 | u32 title_ids_output_pointer = cmd_buff[4]; | ||
| 93 | |||
| 94 | am_titles_list_count[media_type] = cmd_buff[1]; | ||
| 95 | |||
| 96 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 97 | cmd_buff[2] = am_titles_list_count[media_type]; | ||
| 98 | LOG_WARNING( | ||
| 99 | Service_AM, | ||
| 100 | "(STUBBED) media_type=%u, titles_list_count=0x%08X, title_ids_output_pointer=0x%08X", | ||
| 101 | media_type, am_titles_list_count[media_type], title_ids_output_pointer); | ||
| 102 | } | ||
| 103 | |||
| 104 | void GetProgramInfos(Service::Interface* self) { | ||
| 105 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 106 | |||
| 107 | u32 media_type = cmd_buff[1] & 0xFF; | ||
| 108 | u32 title_id_list_pointer = cmd_buff[4]; | ||
| 109 | u32 title_list_pointer = cmd_buff[6]; | ||
| 110 | |||
| 111 | am_titles_count[media_type] = cmd_buff[2]; | ||
| 112 | |||
| 113 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 114 | LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, total_titles=0x%08X, " | ||
| 115 | "title_id_list_pointer=0x%08X, title_list_pointer=0x%08X", | ||
| 116 | media_type, am_titles_count[media_type], title_id_list_pointer, title_list_pointer); | ||
| 117 | } | ||
| 118 | |||
| 119 | void GetDataTitleInfos(Service::Interface* self) { | ||
| 120 | GetProgramInfos(self); | ||
| 121 | |||
| 122 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 123 | } | ||
| 124 | |||
| 125 | void ListDataTitleTicketInfos(Service::Interface* self) { | ||
| 126 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 127 | |||
| 128 | u64 title_id = (static_cast<u64>(cmd_buff[3]) << 32) | cmd_buff[2]; | ||
| 129 | u32 start_index = cmd_buff[4]; | ||
| 130 | u32 ticket_info_pointer = cmd_buff[6]; | ||
| 131 | |||
| 132 | am_ticket_count = cmd_buff[1]; | ||
| 133 | |||
| 134 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 135 | cmd_buff[2] = am_ticket_count; | ||
| 136 | LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64 | ||
| 137 | ", start_index=0x%08X, ticket_info_pointer=0x%08X", | ||
| 138 | am_ticket_count, title_id, start_index, ticket_info_pointer); | ||
| 139 | } | ||
| 140 | |||
| 141 | void GetNumContentInfos(Service::Interface* self) { | ||
| 142 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 143 | |||
| 144 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 145 | cmd_buff[2] = 1; // Number of content infos plus one | ||
| 146 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 147 | } | ||
| 148 | |||
| 149 | void DeleteTicket(Service::Interface* self) { | ||
| 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 151 | |||
| 152 | u64 title_id = (static_cast<u64>(cmd_buff[2]) << 32) | cmd_buff[1]; | ||
| 153 | |||
| 154 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 155 | LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id); | ||
| 156 | } | ||
| 157 | |||
| 158 | void GetNumTickets(Service::Interface* self) { | ||
| 159 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 160 | |||
| 161 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 162 | cmd_buff[2] = am_ticket_count; | ||
| 163 | LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x", am_ticket_count); | ||
| 164 | } | ||
| 165 | |||
| 166 | void GetTicketList(Service::Interface* self) { | ||
| 167 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 168 | |||
| 169 | u32 num_of_skip = cmd_buff[2]; | ||
| 170 | u32 ticket_list_pointer = cmd_buff[4]; | ||
| 171 | |||
| 172 | am_ticket_list_count = cmd_buff[1]; | ||
| 173 | |||
| 174 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 175 | cmd_buff[2] = am_ticket_list_count; | ||
| 176 | LOG_WARNING( | ||
| 177 | Service_AM, | ||
| 178 | "(STUBBED) ticket_list_count=0x%08x, num_of_skip=0x%08x, ticket_list_pointer=0x%08x", | ||
| 179 | am_ticket_list_count, num_of_skip, ticket_list_pointer); | ||
| 180 | } | ||
| 181 | |||
| 182 | void Init() { | ||
| 183 | AddService(new AM_APP_Interface); | ||
| 184 | AddService(new AM_NET_Interface); | ||
| 185 | AddService(new AM_SYS_Interface); | ||
| 186 | AddService(new AM_U_Interface); | ||
| 187 | } | ||
| 188 | |||
| 189 | void Shutdown() {} | ||
| 190 | |||
| 191 | } // namespace AM | ||
| 192 | |||
| 193 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h deleted file mode 100644 index 9bc2ca305..000000000 --- a/src/core/hle/service/am/am.h +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | class Interface; | ||
| 10 | |||
| 11 | namespace AM { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * AM::GetNumPrograms service function | ||
| 15 | * Gets the number of installed titles in the requested media type | ||
| 16 | * Inputs: | ||
| 17 | * 0 : Command header (0x00010040) | ||
| 18 | * 1 : Media type to load the titles from | ||
| 19 | * Outputs: | ||
| 20 | * 1 : Result, 0 on success, otherwise error code | ||
| 21 | * 2 : The number of titles in the requested media type | ||
| 22 | */ | ||
| 23 | void GetNumPrograms(Service::Interface* self); | ||
| 24 | |||
| 25 | /** | ||
| 26 | * AM::FindContentInfos service function | ||
| 27 | * Inputs: | ||
| 28 | * 1 : MediaType | ||
| 29 | * 2-3 : u64, Title ID | ||
| 30 | * 4 : Content count | ||
| 31 | * 6 : Content IDs pointer | ||
| 32 | * 8 : Content Infos pointer | ||
| 33 | * Outputs: | ||
| 34 | * 1 : Result, 0 on success, otherwise error code | ||
| 35 | */ | ||
| 36 | void FindContentInfos(Service::Interface* self); | ||
| 37 | |||
| 38 | /** | ||
| 39 | * AM::ListContentInfos service function | ||
| 40 | * Inputs: | ||
| 41 | * 1 : Content count | ||
| 42 | * 2 : MediaType | ||
| 43 | * 3-4 : u64, Title ID | ||
| 44 | * 5 : Start Index | ||
| 45 | * 7 : Content Infos pointer | ||
| 46 | * Outputs: | ||
| 47 | * 1 : Result, 0 on success, otherwise error code | ||
| 48 | * 2 : Number of content infos returned | ||
| 49 | */ | ||
| 50 | void ListContentInfos(Service::Interface* self); | ||
| 51 | |||
| 52 | /** | ||
| 53 | * AM::DeleteContents service function | ||
| 54 | * Inputs: | ||
| 55 | * 1 : MediaType | ||
| 56 | * 2-3 : u64, Title ID | ||
| 57 | * 4 : Content count | ||
| 58 | * 6 : Content IDs pointer | ||
| 59 | * Outputs: | ||
| 60 | * 1 : Result, 0 on success, otherwise error code | ||
| 61 | */ | ||
| 62 | void DeleteContents(Service::Interface* self); | ||
| 63 | |||
| 64 | /** | ||
| 65 | * AM::GetProgramList service function | ||
| 66 | * Loads information about the desired number of titles from the desired media type into an array | ||
| 67 | * Inputs: | ||
| 68 | * 1 : Title count | ||
| 69 | * 2 : Media type to load the titles from | ||
| 70 | * 4 : Title IDs output pointer | ||
| 71 | * Outputs: | ||
| 72 | * 1 : Result, 0 on success, otherwise error code | ||
| 73 | * 2 : The number of titles loaded from the requested media type | ||
| 74 | */ | ||
| 75 | void GetProgramList(Service::Interface* self); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * AM::GetProgramInfos service function | ||
| 79 | * Inputs: | ||
| 80 | * 1 : u8 Mediatype | ||
| 81 | * 2 : Total titles | ||
| 82 | * 4 : TitleIDList pointer | ||
| 83 | * 6 : TitleList pointer | ||
| 84 | * Outputs: | ||
| 85 | * 1 : Result, 0 on success, otherwise error code | ||
| 86 | */ | ||
| 87 | void GetProgramInfos(Service::Interface* self); | ||
| 88 | |||
| 89 | /** | ||
| 90 | * AM::GetDataTitleInfos service function | ||
| 91 | * Wrapper for AM::GetProgramInfos | ||
| 92 | * Inputs: | ||
| 93 | * 1 : u8 Mediatype | ||
| 94 | * 2 : Total titles | ||
| 95 | * 4 : TitleIDList pointer | ||
| 96 | * 6 : TitleList pointer | ||
| 97 | * Outputs: | ||
| 98 | * 1 : Result, 0 on success, otherwise error code | ||
| 99 | */ | ||
| 100 | void GetDataTitleInfos(Service::Interface* self); | ||
| 101 | |||
| 102 | /** | ||
| 103 | * AM::ListDataTitleTicketInfos service function | ||
| 104 | * Inputs: | ||
| 105 | * 1 : Ticket count | ||
| 106 | * 2-3 : u64, Title ID | ||
| 107 | * 4 : Start Index? | ||
| 108 | * 5 : (TicketCount * 24) << 8 | 0x4 | ||
| 109 | * 6 : Ticket Infos pointer | ||
| 110 | * Outputs: | ||
| 111 | * 1 : Result, 0 on success, otherwise error code | ||
| 112 | * 2 : Number of ticket infos returned | ||
| 113 | */ | ||
| 114 | void ListDataTitleTicketInfos(Service::Interface* self); | ||
| 115 | |||
| 116 | /** | ||
| 117 | * AM::GetNumContentInfos service function | ||
| 118 | * Inputs: | ||
| 119 | * 0 : Command header (0x100100C0) | ||
| 120 | * 1 : MediaType | ||
| 121 | * 2-3 : u64, Title ID | ||
| 122 | * Outputs: | ||
| 123 | * 1 : Result, 0 on success, otherwise error code | ||
| 124 | * 2 : Number of content infos plus one | ||
| 125 | */ | ||
| 126 | void GetNumContentInfos(Service::Interface* self); | ||
| 127 | |||
| 128 | /** | ||
| 129 | * AM::DeleteTicket service function | ||
| 130 | * Inputs: | ||
| 131 | * 1-2 : u64, Title ID | ||
| 132 | * Outputs: | ||
| 133 | * 1 : Result, 0 on success, otherwise error code | ||
| 134 | */ | ||
| 135 | void DeleteTicket(Service::Interface* self); | ||
| 136 | |||
| 137 | /** | ||
| 138 | * AM::GetNumTickets service function | ||
| 139 | * Outputs: | ||
| 140 | * 1 : Result, 0 on success, otherwise error code | ||
| 141 | * 2 : Number of tickets | ||
| 142 | */ | ||
| 143 | void GetNumTickets(Service::Interface* self); | ||
| 144 | |||
| 145 | /** | ||
| 146 | * AM::GetTicketList service function | ||
| 147 | * Inputs: | ||
| 148 | * 1 : Number of TicketList | ||
| 149 | * 2 : Number to skip | ||
| 150 | * 4 : TicketList pointer | ||
| 151 | * Outputs: | ||
| 152 | * 1 : Result, 0 on success, otherwise error code | ||
| 153 | * 2 : Total TicketList | ||
| 154 | */ | ||
| 155 | void GetTicketList(Service::Interface* self); | ||
| 156 | |||
| 157 | /// Initialize AM service | ||
| 158 | void Init(); | ||
| 159 | |||
| 160 | /// Shutdown AM service | ||
| 161 | void Shutdown(); | ||
| 162 | |||
| 163 | } // namespace AM | ||
| 164 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp deleted file mode 100644 index 218375c8f..000000000 --- a/src/core/hle/service/am/am_app.cpp +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/am/am.h" | ||
| 6 | #include "core/hle/service/am/am_app.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x100100C0, GetNumContentInfos, "GetNumContentInfos"}, | ||
| 13 | {0x10020104, FindContentInfos, "FindContentInfos"}, | ||
| 14 | {0x10030142, ListContentInfos, "ListContentInfos"}, | ||
| 15 | {0x10040102, DeleteContents, "DeleteContents"}, | ||
| 16 | {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, | ||
| 17 | {0x10060080, nullptr, "GetNumDataTitleTickets"}, | ||
| 18 | {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, | ||
| 19 | {0x100801C2, nullptr, "GetItemRights"}, | ||
| 20 | {0x100900C0, nullptr, "IsDataTitleInUse"}, | ||
| 21 | {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, | ||
| 22 | {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, | ||
| 23 | {0x100C0142, nullptr, "ListExistingContentInfos"}, | ||
| 24 | {0x100D0084, nullptr, "GetPatchTitleInfos"}, | ||
| 25 | }; | ||
| 26 | |||
| 27 | AM_APP_Interface::AM_APP_Interface() { | ||
| 28 | Register(FunctionTable); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace AM | ||
| 32 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h deleted file mode 100644 index fd6017d14..000000000 --- a/src/core/hle/service/am/am_app.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AM { | ||
| 11 | |||
| 12 | class AM_APP_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | AM_APP_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "am:app"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp deleted file mode 100644 index f3cd1d23f..000000000 --- a/src/core/hle/service/am/am_net.cpp +++ /dev/null | |||
| @@ -1,129 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/am/am.h" | ||
| 6 | #include "core/hle/service/am/am_net.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetNumPrograms, "GetNumPrograms"}, | ||
| 13 | {0x00020082, GetProgramList, "GetProgramList"}, | ||
| 14 | {0x00030084, GetProgramInfos, "GetProgramInfos"}, | ||
| 15 | {0x000400C0, nullptr, "DeleteUserProgram"}, | ||
| 16 | {0x000500C0, nullptr, "GetProductCode"}, | ||
| 17 | {0x000600C0, nullptr, "GetStorageId"}, | ||
| 18 | {0x00070080, DeleteTicket, "DeleteTicket"}, | ||
| 19 | {0x00080000, GetNumTickets, "GetNumTickets"}, | ||
| 20 | {0x00090082, GetTicketList, "GetTicketList"}, | ||
| 21 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 22 | {0x000B0040, nullptr, "GetNumImportTitleContexts"}, | ||
| 23 | {0x000C0082, nullptr, "GetImportTitleContextList"}, | ||
| 24 | {0x000D0084, nullptr, "GetImportTitleContexts"}, | ||
| 25 | {0x000E00C0, nullptr, "DeleteImportTitleContext"}, | ||
| 26 | {0x000F00C0, nullptr, "GetNumImportContentContexts"}, | ||
| 27 | {0x00100102, nullptr, "GetImportContentContextList"}, | ||
| 28 | {0x00110104, nullptr, "GetImportContentContexts"}, | ||
| 29 | {0x00120102, nullptr, "DeleteImportContentContexts"}, | ||
| 30 | {0x00130040, nullptr, "NeedsCleanup"}, | ||
| 31 | {0x00140040, nullptr, "DoCleanup"}, | ||
| 32 | {0x00150040, nullptr, "DeleteAllImportContexts"}, | ||
| 33 | {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, | ||
| 34 | {0x00170044, nullptr, "ImportTwlBackupLegacy"}, | ||
| 35 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 36 | {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, | ||
| 37 | {0x001A00C0, nullptr, "CalcTwlBackupSize"}, | ||
| 38 | {0x001B0144, nullptr, "ExportTwlBackup"}, | ||
| 39 | {0x001C0084, nullptr, "ImportTwlBackup"}, | ||
| 40 | {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, | ||
| 41 | {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, | ||
| 42 | {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, | ||
| 43 | {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, | ||
| 44 | {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, | ||
| 45 | {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, | ||
| 46 | {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, | ||
| 47 | {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, | ||
| 48 | {0x002500C0, nullptr, "CheckContentRights"}, | ||
| 49 | {0x00260044, nullptr, "GetTicketLimitInfos"}, | ||
| 50 | {0x00270044, nullptr, "GetDemoLaunchInfos"}, | ||
| 51 | {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, | ||
| 52 | {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, | ||
| 53 | {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, | ||
| 54 | {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, | ||
| 55 | {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, | ||
| 56 | {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, | ||
| 57 | {0x04010080, nullptr, "UpdateFirmwareTo"}, | ||
| 58 | {0x04020040, nullptr, "BeginImportProgram"}, | ||
| 59 | {0x04030000, nullptr, "BeginImportProgramTemporarily"}, | ||
| 60 | {0x04040002, nullptr, "CancelImportProgram"}, | ||
| 61 | {0x04050002, nullptr, "EndImportProgram"}, | ||
| 62 | {0x04060002, nullptr, "EndImportProgramWithoutCommit"}, | ||
| 63 | {0x040700C2, nullptr, "CommitImportPrograms"}, | ||
| 64 | {0x04080042, nullptr, "GetProgramInfoFromCia"}, | ||
| 65 | {0x04090004, nullptr, "GetSystemMenuDataFromCia"}, | ||
| 66 | {0x040A0002, nullptr, "GetDependencyListFromCia"}, | ||
| 67 | {0x040B0002, nullptr, "GetTransferSizeFromCia"}, | ||
| 68 | {0x040C0002, nullptr, "GetCoreVersionFromCia"}, | ||
| 69 | {0x040D0042, nullptr, "GetRequiredSizeFromCia"}, | ||
| 70 | {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, | ||
| 71 | {0x040F0000, nullptr, "UpdateFirmwareAuto"}, | ||
| 72 | {0x041000C0, nullptr, "DeleteProgram"}, | ||
| 73 | {0x04110044, nullptr, "GetTwlProgramListForReboot"}, | ||
| 74 | {0x04120000, nullptr, "GetSystemUpdaterMutex"}, | ||
| 75 | {0x04130002, nullptr, "GetMetaSizeFromCia"}, | ||
| 76 | {0x04140044, nullptr, "GetMetaDataFromCia"}, | ||
| 77 | {0x04150080, nullptr, "CheckDemoLaunchRights"}, | ||
| 78 | {0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, | ||
| 79 | {0x041700C0, nullptr, "PerpetuateAgbSaveData"}, | ||
| 80 | {0x04180040, nullptr, "BeginImportProgramForOverWrite"}, | ||
| 81 | {0x04190000, nullptr, "BeginImportSystemProgram"}, | ||
| 82 | {0x08010000, nullptr, "BeginImportTicket"}, | ||
| 83 | {0x08020002, nullptr, "CancelImportTicket"}, | ||
| 84 | {0x08030002, nullptr, "EndImportTicket"}, | ||
| 85 | {0x08040100, nullptr, "BeginImportTitle"}, | ||
| 86 | {0x08050000, nullptr, "StopImportTitle"}, | ||
| 87 | {0x080600C0, nullptr, "ResumeImportTitle"}, | ||
| 88 | {0x08070000, nullptr, "CancelImportTitle"}, | ||
| 89 | {0x08080000, nullptr, "EndImportTitle"}, | ||
| 90 | {0x080900C2, nullptr, "CommitImportTitles"}, | ||
| 91 | {0x080A0000, nullptr, "BeginImportTmd"}, | ||
| 92 | {0x080B0002, nullptr, "CancelImportTmd"}, | ||
| 93 | {0x080C0042, nullptr, "EndImportTmd"}, | ||
| 94 | {0x080D0042, nullptr, "CreateImportContentContexts"}, | ||
| 95 | {0x080E0040, nullptr, "BeginImportContent"}, | ||
| 96 | {0x080F0002, nullptr, "StopImportContent"}, | ||
| 97 | {0x08100040, nullptr, "ResumeImportContent"}, | ||
| 98 | {0x08110002, nullptr, "CancelImportContent"}, | ||
| 99 | {0x08120002, nullptr, "EndImportContent"}, | ||
| 100 | {0x08130000, nullptr, "GetNumCurrentImportContentContexts"}, | ||
| 101 | {0x08140042, nullptr, "GetCurrentImportContentContextList"}, | ||
| 102 | {0x08150044, nullptr, "GetCurrentImportContentContexts"}, | ||
| 103 | {0x08160146, nullptr, "Sign"}, | ||
| 104 | {0x08170146, nullptr, "Verify"}, | ||
| 105 | {0x08180042, nullptr, "GetDeviceCert"}, | ||
| 106 | {0x08190108, nullptr, "ImportCertificates"}, | ||
| 107 | {0x081A0042, nullptr, "ImportCertificate"}, | ||
| 108 | {0x081B00C2, nullptr, "CommitImportTitlesAndUpdateFirmwareAuto"}, | ||
| 109 | {0x081C0100, nullptr, "DeleteTicketId"}, | ||
| 110 | {0x081D0080, nullptr, "GetNumTicketIds"}, | ||
| 111 | {0x081E0102, nullptr, "GetTicketIdList"}, | ||
| 112 | {0x081F0080, nullptr, "GetNumTicketsOfProgram"}, | ||
| 113 | {0x08200102, nullptr, "ListTicketInfos"}, | ||
| 114 | {0x08210142, nullptr, "GetRightsOnlyTicketData"}, | ||
| 115 | {0x08220000, nullptr, "GetNumCurrentContentInfos"}, | ||
| 116 | {0x08230044, nullptr, "FindCurrentContentInfos"}, | ||
| 117 | {0x08240082, nullptr, "ListCurrentContentInfos"}, | ||
| 118 | {0x08250102, nullptr, "CalculateContextRequiredSize"}, | ||
| 119 | {0x08260042, nullptr, "UpdateImportContentContexts"}, | ||
| 120 | {0x08270000, nullptr, "DeleteAllDemoLaunchInfos"}, | ||
| 121 | {0x082800C0, nullptr, "BeginImportTitleForOverWrite"}, | ||
| 122 | }; | ||
| 123 | |||
| 124 | AM_NET_Interface::AM_NET_Interface() { | ||
| 125 | Register(FunctionTable); | ||
| 126 | } | ||
| 127 | |||
| 128 | } // namespace AM | ||
| 129 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h deleted file mode 100644 index 25d2c3f23..000000000 --- a/src/core/hle/service/am/am_net.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AM { | ||
| 11 | |||
| 12 | class AM_NET_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | AM_NET_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "am:net"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp deleted file mode 100644 index 949b3591d..000000000 --- a/src/core/hle/service/am/am_sys.cpp +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/am/am.h" | ||
| 6 | #include "core/hle/service/am/am_sys.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetNumPrograms, "GetNumPrograms"}, | ||
| 13 | {0x00020082, GetProgramList, "GetProgramList"}, | ||
| 14 | {0x00030084, GetProgramInfos, "GetProgramInfos"}, | ||
| 15 | {0x000400C0, nullptr, "DeleteUserProgram"}, | ||
| 16 | {0x000500C0, nullptr, "GetProductCode"}, | ||
| 17 | {0x000600C0, nullptr, "GetStorageId"}, | ||
| 18 | {0x00070080, DeleteTicket, "DeleteTicket"}, | ||
| 19 | {0x00080000, GetNumTickets, "GetNumTickets"}, | ||
| 20 | {0x00090082, GetTicketList, "GetTicketList"}, | ||
| 21 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 22 | {0x000B0040, nullptr, "GetNumImportTitleContexts"}, | ||
| 23 | {0x000C0082, nullptr, "GetImportTitleContextList"}, | ||
| 24 | {0x000D0084, nullptr, "GetImportTitleContexts"}, | ||
| 25 | {0x000E00C0, nullptr, "DeleteImportTitleContext"}, | ||
| 26 | {0x000F00C0, nullptr, "GetNumImportContentContexts"}, | ||
| 27 | {0x00100102, nullptr, "GetImportContentContextList"}, | ||
| 28 | {0x00110104, nullptr, "GetImportContentContexts"}, | ||
| 29 | {0x00120102, nullptr, "DeleteImportContentContexts"}, | ||
| 30 | {0x00130040, nullptr, "NeedsCleanup"}, | ||
| 31 | {0x00140040, nullptr, "DoCleanup"}, | ||
| 32 | {0x00150040, nullptr, "DeleteAllImportContexts"}, | ||
| 33 | {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, | ||
| 34 | {0x00170044, nullptr, "ImportTwlBackupLegacy"}, | ||
| 35 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 36 | {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, | ||
| 37 | {0x001A00C0, nullptr, "CalcTwlBackupSize"}, | ||
| 38 | {0x001B0144, nullptr, "ExportTwlBackup"}, | ||
| 39 | {0x001C0084, nullptr, "ImportTwlBackup"}, | ||
| 40 | {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, | ||
| 41 | {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, | ||
| 42 | {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, | ||
| 43 | {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, | ||
| 44 | {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, | ||
| 45 | {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, | ||
| 46 | {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, | ||
| 47 | {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, | ||
| 48 | {0x002500C0, nullptr, "CheckContentRights"}, | ||
| 49 | {0x00260044, nullptr, "GetTicketLimitInfos"}, | ||
| 50 | {0x00270044, nullptr, "GetDemoLaunchInfos"}, | ||
| 51 | {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, | ||
| 52 | {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, | ||
| 53 | {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, | ||
| 54 | {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, | ||
| 55 | {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, | ||
| 56 | {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, | ||
| 57 | {0x100100C0, GetNumContentInfos, "GetNumContentInfos"}, | ||
| 58 | {0x10020104, FindContentInfos, "FindContentInfos"}, | ||
| 59 | {0x10030142, ListContentInfos, "ListContentInfos"}, | ||
| 60 | {0x10040102, DeleteContents, "DeleteContents"}, | ||
| 61 | {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"}, | ||
| 62 | {0x10060080, nullptr, "GetNumDataTitleTickets"}, | ||
| 63 | {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, | ||
| 64 | {0x100801C2, nullptr, "GetItemRights"}, | ||
| 65 | {0x100900C0, nullptr, "IsDataTitleInUse"}, | ||
| 66 | {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, | ||
| 67 | {0x100B00C0, nullptr, "GetNumExistingContentInfos"}, | ||
| 68 | {0x100C0142, nullptr, "ListExistingContentInfos"}, | ||
| 69 | {0x100D0084, nullptr, "GetPatchTitleInfos"}, | ||
| 70 | }; | ||
| 71 | |||
| 72 | AM_SYS_Interface::AM_SYS_Interface() { | ||
| 73 | Register(FunctionTable); | ||
| 74 | } | ||
| 75 | |||
| 76 | } // namespace AM | ||
| 77 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h deleted file mode 100644 index b114f1d35..000000000 --- a/src/core/hle/service/am/am_sys.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AM { | ||
| 11 | |||
| 12 | class AM_SYS_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | AM_SYS_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "am:sys"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp deleted file mode 100644 index 354d51610..000000000 --- a/src/core/hle/service/am/am_u.cpp +++ /dev/null | |||
| @@ -1,89 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/am/am.h" | ||
| 6 | #include "core/hle/service/am/am_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace AM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetNumPrograms, "GetNumPrograms"}, | ||
| 13 | {0x00020082, GetProgramList, "GetProgramList"}, | ||
| 14 | {0x00030084, GetProgramInfos, "GetProgramInfos"}, | ||
| 15 | {0x000400C0, nullptr, "DeleteUserProgram"}, | ||
| 16 | {0x000500C0, nullptr, "GetProductCode"}, | ||
| 17 | {0x000600C0, nullptr, "GetStorageId"}, | ||
| 18 | {0x00070080, DeleteTicket, "DeleteTicket"}, | ||
| 19 | {0x00080000, GetNumTickets, "GetNumTickets"}, | ||
| 20 | {0x00090082, GetTicketList, "GetTicketList"}, | ||
| 21 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 22 | {0x000B0040, nullptr, "GetNumImportTitleContexts"}, | ||
| 23 | {0x000C0082, nullptr, "GetImportTitleContextList"}, | ||
| 24 | {0x000D0084, nullptr, "GetImportTitleContexts"}, | ||
| 25 | {0x000E00C0, nullptr, "DeleteImportTitleContext"}, | ||
| 26 | {0x000F00C0, nullptr, "GetNumImportContentContexts"}, | ||
| 27 | {0x00100102, nullptr, "GetImportContentContextList"}, | ||
| 28 | {0x00110104, nullptr, "GetImportContentContexts"}, | ||
| 29 | {0x00120102, nullptr, "DeleteImportContentContexts"}, | ||
| 30 | {0x00130040, nullptr, "NeedsCleanup"}, | ||
| 31 | {0x00140040, nullptr, "DoCleanup"}, | ||
| 32 | {0x00150040, nullptr, "DeleteAllImportContexts"}, | ||
| 33 | {0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, | ||
| 34 | {0x00170044, nullptr, "ImportTwlBackupLegacy"}, | ||
| 35 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 36 | {0x00190040, nullptr, "QueryAvailableTitleDatabase"}, | ||
| 37 | {0x001A00C0, nullptr, "CalcTwlBackupSize"}, | ||
| 38 | {0x001B0144, nullptr, "ExportTwlBackup"}, | ||
| 39 | {0x001C0084, nullptr, "ImportTwlBackup"}, | ||
| 40 | {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"}, | ||
| 41 | {0x001E00C8, nullptr, "ReadTwlBackupInfo"}, | ||
| 42 | {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"}, | ||
| 43 | {0x00200000, nullptr, "GetTwlArchiveResourceInfo"}, | ||
| 44 | {0x00210042, nullptr, "GetPersonalizedTicketInfoList"}, | ||
| 45 | {0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, | ||
| 46 | {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, | ||
| 47 | {0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, | ||
| 48 | {0x002500C0, nullptr, "CheckContentRights"}, | ||
| 49 | {0x00260044, nullptr, "GetTicketLimitInfos"}, | ||
| 50 | {0x00270044, nullptr, "GetDemoLaunchInfos"}, | ||
| 51 | {0x00280108, nullptr, "ReadTwlBackupInfoEx"}, | ||
| 52 | {0x00290082, nullptr, "DeleteUserProgramsAtomically"}, | ||
| 53 | {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, | ||
| 54 | {0x002B0142, nullptr, "ListExistingContentInfosSystem"}, | ||
| 55 | {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, | ||
| 56 | {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, | ||
| 57 | {0x04010080, nullptr, "UpdateFirmwareTo"}, | ||
| 58 | {0x04020040, nullptr, "BeginImportProgram"}, | ||
| 59 | {0x04030000, nullptr, "BeginImportProgramTemporarily"}, | ||
| 60 | {0x04040002, nullptr, "CancelImportProgram"}, | ||
| 61 | {0x04050002, nullptr, "EndImportProgram"}, | ||
| 62 | {0x04060002, nullptr, "EndImportProgramWithoutCommit"}, | ||
| 63 | {0x040700C2, nullptr, "CommitImportPrograms"}, | ||
| 64 | {0x04080042, nullptr, "GetProgramInfoFromCia"}, | ||
| 65 | {0x04090004, nullptr, "GetSystemMenuDataFromCia"}, | ||
| 66 | {0x040A0002, nullptr, "GetDependencyListFromCia"}, | ||
| 67 | {0x040B0002, nullptr, "GetTransferSizeFromCia"}, | ||
| 68 | {0x040C0002, nullptr, "GetCoreVersionFromCia"}, | ||
| 69 | {0x040D0042, nullptr, "GetRequiredSizeFromCia"}, | ||
| 70 | {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, | ||
| 71 | {0x040F0000, nullptr, "UpdateFirmwareAuto"}, | ||
| 72 | {0x041000C0, nullptr, "DeleteProgram"}, | ||
| 73 | {0x04110044, nullptr, "GetTwlProgramListForReboot"}, | ||
| 74 | {0x04120000, nullptr, "GetSystemUpdaterMutex"}, | ||
| 75 | {0x04130002, nullptr, "GetMetaSizeFromCia"}, | ||
| 76 | {0x04140044, nullptr, "GetMetaDataFromCia"}, | ||
| 77 | {0x04150080, nullptr, "CheckDemoLaunchRights"}, | ||
| 78 | {0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, | ||
| 79 | {0x041700C0, nullptr, "PerpetuateAgbSaveData"}, | ||
| 80 | {0x04180040, nullptr, "BeginImportProgramForOverWrite"}, | ||
| 81 | {0x04190000, nullptr, "BeginImportSystemProgram"}, | ||
| 82 | }; | ||
| 83 | |||
| 84 | AM_U_Interface::AM_U_Interface() { | ||
| 85 | Register(FunctionTable); | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace AM | ||
| 89 | } // namespace Service | ||
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h deleted file mode 100644 index 3b2454b6c..000000000 --- a/src/core/hle/service/am/am_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace AM { | ||
| 11 | |||
| 12 | class AM_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | AM_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "am:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace AM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp deleted file mode 100644 index 912ab550d..000000000 --- a/src/core/hle/service/apt/apt.cpp +++ /dev/null | |||
| @@ -1,1124 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <boost/optional.hpp> | ||
| 6 | #include "common/common_paths.h" | ||
| 7 | #include "common/file_util.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/file_sys/file_backend.h" | ||
| 11 | #include "core/hle/applets/applet.h" | ||
| 12 | #include "core/hle/kernel/event.h" | ||
| 13 | #include "core/hle/kernel/mutex.h" | ||
| 14 | #include "core/hle/kernel/process.h" | ||
| 15 | #include "core/hle/kernel/shared_memory.h" | ||
| 16 | #include "core/hle/romfs.h" | ||
| 17 | #include "core/hle/service/apt/apt.h" | ||
| 18 | #include "core/hle/service/apt/apt_a.h" | ||
| 19 | #include "core/hle/service/apt/apt_s.h" | ||
| 20 | #include "core/hle/service/apt/apt_u.h" | ||
| 21 | #include "core/hle/service/apt/bcfnt/bcfnt.h" | ||
| 22 | #include "core/hle/service/cfg/cfg.h" | ||
| 23 | #include "core/hle/service/fs/archive.h" | ||
| 24 | #include "core/hle/service/ptm/ptm.h" | ||
| 25 | #include "core/hle/service/service.h" | ||
| 26 | #include "core/hw/aes/ccm.h" | ||
| 27 | #include "core/hw/aes/key.h" | ||
| 28 | |||
| 29 | namespace Service { | ||
| 30 | namespace APT { | ||
| 31 | |||
| 32 | /// Handle to shared memory region designated to for shared system font | ||
| 33 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | ||
| 34 | static bool shared_font_loaded = false; | ||
| 35 | static bool shared_font_relocated = false; | ||
| 36 | |||
| 37 | static Kernel::SharedPtr<Kernel::Mutex> lock; | ||
| 38 | |||
| 39 | static u32 cpu_percent; ///< CPU time available to the running application | ||
| 40 | |||
| 41 | // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode | ||
| 42 | static u8 unknown_ns_state_field; | ||
| 43 | |||
| 44 | static ScreencapPostPermission screen_capture_post_permission; | ||
| 45 | |||
| 46 | /// Parameter data to be returned in the next call to Glance/ReceiveParameter. | ||
| 47 | /// TODO(Subv): Use std::optional once we migrate to C++17. | ||
| 48 | static boost::optional<MessageParameter> next_parameter; | ||
| 49 | |||
| 50 | enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; | ||
| 51 | |||
| 52 | static constexpr size_t NumAppletSlot = 4; | ||
| 53 | |||
| 54 | enum class AppletSlot : u8 { | ||
| 55 | Application, | ||
| 56 | SystemApplet, | ||
| 57 | HomeMenu, | ||
| 58 | LibraryApplet, | ||
| 59 | |||
| 60 | // An invalid tag | ||
| 61 | Error, | ||
| 62 | }; | ||
| 63 | |||
| 64 | union AppletAttributes { | ||
| 65 | u32 raw; | ||
| 66 | |||
| 67 | BitField<0, 3, u32> applet_pos; | ||
| 68 | BitField<29, 1, u32> is_home_menu; | ||
| 69 | |||
| 70 | AppletAttributes() : raw(0) {} | ||
| 71 | AppletAttributes(u32 attributes) : raw(attributes) {} | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct AppletSlotData { | ||
| 75 | AppletId applet_id; | ||
| 76 | AppletSlot slot; | ||
| 77 | bool registered; | ||
| 78 | AppletAttributes attributes; | ||
| 79 | Kernel::SharedPtr<Kernel::Event> notification_event; | ||
| 80 | Kernel::SharedPtr<Kernel::Event> parameter_event; | ||
| 81 | }; | ||
| 82 | |||
| 83 | // Holds data about the concurrently running applets in the system. | ||
| 84 | static std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; | ||
| 85 | |||
| 86 | // This overload returns nullptr if no applet with the specified id has been started. | ||
| 87 | static AppletSlotData* GetAppletSlotData(AppletId id) { | ||
| 88 | auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { | ||
| 89 | return &applet_slots[static_cast<size_t>(slot)]; | ||
| 90 | }; | ||
| 91 | |||
| 92 | if (id == AppletId::Application) { | ||
| 93 | auto* slot = GetSlot(AppletSlot::Application); | ||
| 94 | if (slot->applet_id != AppletId::None) | ||
| 95 | return slot; | ||
| 96 | |||
| 97 | return nullptr; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (id == AppletId::AnySystemApplet) { | ||
| 101 | auto* system_slot = GetSlot(AppletSlot::SystemApplet); | ||
| 102 | if (system_slot->applet_id != AppletId::None) | ||
| 103 | return system_slot; | ||
| 104 | |||
| 105 | // The Home Menu is also a system applet, but it lives in its own slot to be able to run | ||
| 106 | // concurrently with other system applets. | ||
| 107 | auto* home_slot = GetSlot(AppletSlot::HomeMenu); | ||
| 108 | if (home_slot->applet_id != AppletId::None) | ||
| 109 | return home_slot; | ||
| 110 | |||
| 111 | return nullptr; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { | ||
| 115 | auto* slot = GetSlot(AppletSlot::LibraryApplet); | ||
| 116 | if (slot->applet_id == AppletId::None) | ||
| 117 | return nullptr; | ||
| 118 | |||
| 119 | u32 applet_pos = slot->attributes.applet_pos; | ||
| 120 | |||
| 121 | if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) | ||
| 122 | return slot; | ||
| 123 | |||
| 124 | if (id == AppletId::AnySysLibraryApplet && | ||
| 125 | applet_pos == static_cast<u32>(AppletPos::SysLibrary)) | ||
| 126 | return slot; | ||
| 127 | |||
| 128 | return nullptr; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { | ||
| 132 | auto* slot = GetSlot(AppletSlot::HomeMenu); | ||
| 133 | if (slot->applet_id != AppletId::None) | ||
| 134 | return slot; | ||
| 135 | |||
| 136 | return nullptr; | ||
| 137 | } | ||
| 138 | |||
| 139 | for (auto& slot : applet_slots) { | ||
| 140 | if (slot.applet_id == id) | ||
| 141 | return &slot; | ||
| 142 | } | ||
| 143 | |||
| 144 | return nullptr; | ||
| 145 | } | ||
| 146 | |||
| 147 | static AppletSlotData* GetAppletSlotData(AppletAttributes attributes) { | ||
| 148 | // Mapping from AppletPos to AppletSlot | ||
| 149 | static constexpr std::array<AppletSlot, 6> applet_position_slots = { | ||
| 150 | AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, | ||
| 151 | AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; | ||
| 152 | |||
| 153 | u32 applet_pos = attributes.applet_pos; | ||
| 154 | if (applet_pos >= applet_position_slots.size()) | ||
| 155 | return nullptr; | ||
| 156 | |||
| 157 | AppletSlot slot = applet_position_slots[applet_pos]; | ||
| 158 | |||
| 159 | if (slot == AppletSlot::Error) | ||
| 160 | return nullptr; | ||
| 161 | |||
| 162 | // The Home Menu is a system applet, however, it has its own applet slot so that it can run | ||
| 163 | // concurrently with other system applets. | ||
| 164 | if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) | ||
| 165 | return &applet_slots[static_cast<size_t>(AppletSlot::HomeMenu)]; | ||
| 166 | |||
| 167 | return &applet_slots[static_cast<size_t>(slot)]; | ||
| 168 | } | ||
| 169 | |||
| 170 | void SendParameter(const MessageParameter& parameter) { | ||
| 171 | next_parameter = parameter; | ||
| 172 | // Signal the event to let the receiver know that a new parameter is ready to be read | ||
| 173 | auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); | ||
| 174 | if (slot_data == nullptr) { | ||
| 175 | LOG_DEBUG(Service_APT, "No applet was registered with the id %03X", | ||
| 176 | parameter.destination_id); | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | |||
| 180 | slot_data->parameter_event->Signal(); | ||
| 181 | } | ||
| 182 | |||
| 183 | void Initialize(Service::Interface* self) { | ||
| 184 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 | ||
| 185 | u32 app_id = rp.Pop<u32>(); | ||
| 186 | u32 attributes = rp.Pop<u32>(); | ||
| 187 | |||
| 188 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes); | ||
| 189 | |||
| 190 | auto* const slot_data = GetAppletSlotData(attributes); | ||
| 191 | |||
| 192 | // Note: The real NS service does not check if the attributes value is valid before accessing | ||
| 193 | // the data in the array | ||
| 194 | ASSERT_MSG(slot_data, "Invalid application attributes"); | ||
| 195 | |||
| 196 | if (slot_data->registered) { | ||
| 197 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 198 | rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, | ||
| 199 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 203 | slot_data->applet_id = static_cast<AppletId>(app_id); | ||
| 204 | slot_data->attributes.raw = attributes; | ||
| 205 | |||
| 206 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | ||
| 207 | rb.Push(RESULT_SUCCESS); | ||
| 208 | rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(), | ||
| 209 | Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap()); | ||
| 210 | |||
| 211 | if (slot_data->applet_id == AppletId::Application || | ||
| 212 | slot_data->applet_id == AppletId::HomeMenu) { | ||
| 213 | // Initialize the APT parameter to wake up the application. | ||
| 214 | next_parameter.emplace(); | ||
| 215 | next_parameter->signal = static_cast<u32>(SignalType::Wakeup); | ||
| 216 | next_parameter->sender_id = static_cast<u32>(AppletId::None); | ||
| 217 | next_parameter->destination_id = app_id; | ||
| 218 | // Not signaling the parameter event will cause the application (or Home Menu) to hang | ||
| 219 | // during startup. In the real console, it is usually the Kernel and Home Menu who cause NS | ||
| 220 | // to signal the HomeMenu and Application parameter events, respectively. | ||
| 221 | slot_data->parameter_event->Signal(); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | static u32 DecompressLZ11(const u8* in, u8* out) { | ||
| 226 | u32_le decompressed_size; | ||
| 227 | memcpy(&decompressed_size, in, sizeof(u32)); | ||
| 228 | in += 4; | ||
| 229 | |||
| 230 | u8 type = decompressed_size & 0xFF; | ||
| 231 | ASSERT(type == 0x11); | ||
| 232 | decompressed_size >>= 8; | ||
| 233 | |||
| 234 | u32 current_out_size = 0; | ||
| 235 | u8 flags = 0, mask = 1; | ||
| 236 | while (current_out_size < decompressed_size) { | ||
| 237 | if (mask == 1) { | ||
| 238 | flags = *(in++); | ||
| 239 | mask = 0x80; | ||
| 240 | } else { | ||
| 241 | mask >>= 1; | ||
| 242 | } | ||
| 243 | |||
| 244 | if (flags & mask) { | ||
| 245 | u8 byte1 = *(in++); | ||
| 246 | u32 length = byte1 >> 4; | ||
| 247 | u32 offset; | ||
| 248 | if (length == 0) { | ||
| 249 | u8 byte2 = *(in++); | ||
| 250 | u8 byte3 = *(in++); | ||
| 251 | length = (((byte1 & 0x0F) << 4) | (byte2 >> 4)) + 0x11; | ||
| 252 | offset = (((byte2 & 0x0F) << 8) | byte3) + 0x1; | ||
| 253 | } else if (length == 1) { | ||
| 254 | u8 byte2 = *(in++); | ||
| 255 | u8 byte3 = *(in++); | ||
| 256 | u8 byte4 = *(in++); | ||
| 257 | length = (((byte1 & 0x0F) << 12) | (byte2 << 4) | (byte3 >> 4)) + 0x111; | ||
| 258 | offset = (((byte3 & 0x0F) << 8) | byte4) + 0x1; | ||
| 259 | } else { | ||
| 260 | u8 byte2 = *(in++); | ||
| 261 | length = (byte1 >> 4) + 0x1; | ||
| 262 | offset = (((byte1 & 0x0F) << 8) | byte2) + 0x1; | ||
| 263 | } | ||
| 264 | |||
| 265 | for (u32 i = 0; i < length; i++) { | ||
| 266 | *out = *(out - offset); | ||
| 267 | ++out; | ||
| 268 | } | ||
| 269 | |||
| 270 | current_out_size += length; | ||
| 271 | } else { | ||
| 272 | *(out++) = *(in++); | ||
| 273 | current_out_size++; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | return decompressed_size; | ||
| 277 | } | ||
| 278 | |||
| 279 | static bool LoadSharedFont() { | ||
| 280 | u8 font_region_code; | ||
| 281 | switch (CFG::GetRegionValue()) { | ||
| 282 | case 4: // CHN | ||
| 283 | font_region_code = 2; | ||
| 284 | break; | ||
| 285 | case 5: // KOR | ||
| 286 | font_region_code = 3; | ||
| 287 | break; | ||
| 288 | case 6: // TWN | ||
| 289 | font_region_code = 4; | ||
| 290 | break; | ||
| 291 | default: // JPN/EUR/USA | ||
| 292 | font_region_code = 1; | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | |||
| 296 | const u64_le shared_font_archive_id_low = 0x0004009b00014002 | ((font_region_code - 1) << 8); | ||
| 297 | const u64_le shared_font_archive_id_high = 0x00000001ffffff00; | ||
| 298 | std::vector<u8> shared_font_archive_id(16); | ||
| 299 | std::memcpy(&shared_font_archive_id[0], &shared_font_archive_id_low, sizeof(u64)); | ||
| 300 | std::memcpy(&shared_font_archive_id[8], &shared_font_archive_id_high, sizeof(u64)); | ||
| 301 | FileSys::Path archive_path(shared_font_archive_id); | ||
| 302 | auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::NCCH, archive_path); | ||
| 303 | if (archive_result.Failed()) | ||
| 304 | return false; | ||
| 305 | |||
| 306 | std::vector<u8> romfs_path(20, 0); // 20-byte all zero path for opening RomFS | ||
| 307 | FileSys::Path file_path(romfs_path); | ||
| 308 | FileSys::Mode open_mode = {}; | ||
| 309 | open_mode.read_flag.Assign(1); | ||
| 310 | auto file_result = Service::FS::OpenFileFromArchive(*archive_result, file_path, open_mode); | ||
| 311 | if (file_result.Failed()) | ||
| 312 | return false; | ||
| 313 | |||
| 314 | auto romfs = std::move(file_result).Unwrap(); | ||
| 315 | std::vector<u8> romfs_buffer(romfs->backend->GetSize()); | ||
| 316 | romfs->backend->Read(0, romfs_buffer.size(), romfs_buffer.data()); | ||
| 317 | romfs->backend->Close(); | ||
| 318 | |||
| 319 | const char16_t* file_name[4] = {u"cbf_std.bcfnt.lz", u"cbf_zh-Hans-CN.bcfnt.lz", | ||
| 320 | u"cbf_ko-Hang-KR.bcfnt.lz", u"cbf_zh-Hant-TW.bcfnt.lz"}; | ||
| 321 | const u8* font_file = | ||
| 322 | RomFS::GetFilePointer(romfs_buffer.data(), {file_name[font_region_code - 1]}); | ||
| 323 | if (font_file == nullptr) | ||
| 324 | return false; | ||
| 325 | |||
| 326 | struct { | ||
| 327 | u32_le status; | ||
| 328 | u32_le region; | ||
| 329 | u32_le decompressed_size; | ||
| 330 | INSERT_PADDING_WORDS(0x1D); | ||
| 331 | } shared_font_header{}; | ||
| 332 | static_assert(sizeof(shared_font_header) == 0x80, "shared_font_header has incorrect size"); | ||
| 333 | |||
| 334 | shared_font_header.status = 2; // successfully loaded | ||
| 335 | shared_font_header.region = font_region_code; | ||
| 336 | shared_font_header.decompressed_size = | ||
| 337 | DecompressLZ11(font_file, shared_font_mem->GetPointer(0x80)); | ||
| 338 | std::memcpy(shared_font_mem->GetPointer(), &shared_font_header, sizeof(shared_font_header)); | ||
| 339 | *shared_font_mem->GetPointer(0x83) = 'U'; // Change the magic from "CFNT" to "CFNU" | ||
| 340 | |||
| 341 | return true; | ||
| 342 | } | ||
| 343 | |||
| 344 | static bool LoadLegacySharedFont() { | ||
| 345 | // This is the legacy method to load shared font. | ||
| 346 | // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header | ||
| 347 | // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided | ||
| 348 | // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file | ||
| 349 | // "shared_font.bin" in the Citra "sysdata" directory. | ||
| 350 | std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; | ||
| 351 | |||
| 352 | FileUtil::CreateFullPath(filepath); // Create path if not already created | ||
| 353 | FileUtil::IOFile file(filepath, "rb"); | ||
| 354 | if (file.IsOpen()) { | ||
| 355 | file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize()); | ||
| 356 | return true; | ||
| 357 | } | ||
| 358 | |||
| 359 | return false; | ||
| 360 | } | ||
| 361 | |||
| 362 | void GetSharedFont(Service::Interface* self) { | ||
| 363 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 | ||
| 364 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||
| 365 | |||
| 366 | // Log in telemetry if the game uses the shared font | ||
| 367 | Core::Telemetry().AddField(Telemetry::FieldType::Session, "RequiresSharedFont", true); | ||
| 368 | |||
| 369 | if (!shared_font_loaded) { | ||
| 370 | // On real 3DS, font loading happens on booting. However, we load it on demand to coordinate | ||
| 371 | // with CFG region auto configuration, which happens later than APT initialization. | ||
| 372 | if (LoadSharedFont()) { | ||
| 373 | shared_font_loaded = true; | ||
| 374 | } else if (LoadLegacySharedFont()) { | ||
| 375 | LOG_WARNING(Service_APT, "Loaded shared font by legacy method"); | ||
| 376 | shared_font_loaded = true; | ||
| 377 | } else { | ||
| 378 | LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | ||
| 379 | rb.Push<u32>(-1); // TODO: Find the right error code | ||
| 380 | rb.Skip(1 + 2, true); | ||
| 381 | Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSharedFont); | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | // The shared font has to be relocated to the new address before being passed to the | ||
| 387 | // application. | ||
| 388 | VAddr target_address = | ||
| 389 | Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address).value(); | ||
| 390 | if (!shared_font_relocated) { | ||
| 391 | BCFNT::RelocateSharedFont(shared_font_mem, target_address); | ||
| 392 | shared_font_relocated = true; | ||
| 393 | } | ||
| 394 | |||
| 395 | rb.Push(RESULT_SUCCESS); // No error | ||
| 396 | // Since the SharedMemory interface doesn't provide the address at which the memory was | ||
| 397 | // allocated, the real APT service calculates this address by scanning the entire address space | ||
| 398 | // (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font. | ||
| 399 | rb.Push(target_address); | ||
| 400 | rb.PushCopyHandles(Kernel::g_handle_table.Create(shared_font_mem).Unwrap()); | ||
| 401 | } | ||
| 402 | |||
| 403 | void NotifyToWait(Service::Interface* self) { | ||
| 404 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x43, 1, 0); // 0x430040 | ||
| 405 | u32 app_id = rp.Pop<u32>(); | ||
| 406 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 407 | rb.Push(RESULT_SUCCESS); // No error | ||
| 408 | LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); | ||
| 409 | } | ||
| 410 | |||
| 411 | void GetLockHandle(Service::Interface* self) { | ||
| 412 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x10040 | ||
| 413 | |||
| 414 | // Bits [0:2] are the applet type (System, Library, etc) | ||
| 415 | // Bit 5 tells the application that there's a pending APT parameter, | ||
| 416 | // this will cause the app to wait until parameter_event is signaled. | ||
| 417 | u32 applet_attributes = rp.Pop<u32>(); | ||
| 418 | IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | ||
| 419 | rb.Push(RESULT_SUCCESS); // No error | ||
| 420 | |||
| 421 | // TODO(Subv): The output attributes should have an AppletPos of either Library or System | | ||
| 422 | // Library (depending on the type of the last launched applet) if the input attributes' | ||
| 423 | // AppletPos has the Library bit set. | ||
| 424 | |||
| 425 | rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. | ||
| 426 | rb.Push<u32>(0); // Least significant bit = power button state | ||
| 427 | Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).Unwrap(); | ||
| 428 | rb.PushCopyHandles(handle_copy); | ||
| 429 | |||
| 430 | LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", handle_copy, | ||
| 431 | applet_attributes); | ||
| 432 | } | ||
| 433 | |||
| 434 | void Enable(Service::Interface* self) { | ||
| 435 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 | ||
| 436 | u32 attributes = rp.Pop<u32>(); | ||
| 437 | |||
| 438 | LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); | ||
| 439 | |||
| 440 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 441 | |||
| 442 | auto* const slot_data = GetAppletSlotData(attributes); | ||
| 443 | |||
| 444 | if (!slot_data) { | ||
| 445 | rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, | ||
| 446 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 447 | return; | ||
| 448 | } | ||
| 449 | |||
| 450 | slot_data->registered = true; | ||
| 451 | |||
| 452 | rb.Push(RESULT_SUCCESS); | ||
| 453 | } | ||
| 454 | |||
| 455 | void GetAppletManInfo(Service::Interface* self) { | ||
| 456 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 1, 0); // 0x50040 | ||
| 457 | u32 unk = rp.Pop<u32>(); | ||
| 458 | IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); | ||
| 459 | rb.Push(RESULT_SUCCESS); // No error | ||
| 460 | rb.Push<u32>(0); | ||
| 461 | rb.Push<u32>(0); | ||
| 462 | rb.Push(static_cast<u32>(AppletId::HomeMenu)); // Home menu AppID | ||
| 463 | rb.Push(static_cast<u32>(AppletId::Application)); // TODO(purpasmart96): Do this correctly | ||
| 464 | |||
| 465 | LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); | ||
| 466 | } | ||
| 467 | |||
| 468 | void IsRegistered(Service::Interface* self) { | ||
| 469 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 | ||
| 470 | AppletId app_id = static_cast<AppletId>(rp.Pop<u32>()); | ||
| 471 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 472 | rb.Push(RESULT_SUCCESS); // No error | ||
| 473 | |||
| 474 | auto* const slot_data = GetAppletSlotData(app_id); | ||
| 475 | |||
| 476 | // Check if an LLE applet was registered first, then fallback to HLE applets | ||
| 477 | bool is_registered = slot_data && slot_data->registered; | ||
| 478 | |||
| 479 | if (!is_registered) { | ||
| 480 | if (app_id == AppletId::AnyLibraryApplet) { | ||
| 481 | is_registered = HLE::Applets::IsLibraryAppletRunning(); | ||
| 482 | } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { | ||
| 483 | // The applet exists, set it as registered. | ||
| 484 | is_registered = true; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | rb.Push(is_registered); | ||
| 489 | |||
| 490 | LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id)); | ||
| 491 | } | ||
| 492 | |||
| 493 | void InquireNotification(Service::Interface* self) { | ||
| 494 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 1, 0); // 0xB0040 | ||
| 495 | u32 app_id = rp.Pop<u32>(); | ||
| 496 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 497 | rb.Push(RESULT_SUCCESS); // No error | ||
| 498 | rb.Push(static_cast<u32>(SignalType::None)); // Signal type | ||
| 499 | LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); | ||
| 500 | } | ||
| 501 | |||
| 502 | void SendParameter(Service::Interface* self) { | ||
| 503 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104 | ||
| 504 | u32 src_app_id = rp.Pop<u32>(); | ||
| 505 | u32 dst_app_id = rp.Pop<u32>(); | ||
| 506 | u32 signal_type = rp.Pop<u32>(); | ||
| 507 | u32 buffer_size = rp.Pop<u32>(); | ||
| 508 | Kernel::Handle handle = rp.PopHandle(); | ||
| 509 | size_t size; | ||
| 510 | VAddr buffer = rp.PopStaticBuffer(&size); | ||
| 511 | |||
| 512 | LOG_DEBUG(Service_APT, | ||
| 513 | "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," | ||
| 514 | "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", | ||
| 515 | src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); | ||
| 516 | |||
| 517 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 518 | |||
| 519 | // A new parameter can not be sent if the previous one hasn't been consumed yet | ||
| 520 | if (next_parameter) { | ||
| 521 | rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, | ||
| 522 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 523 | return; | ||
| 524 | } | ||
| 525 | |||
| 526 | MessageParameter param; | ||
| 527 | param.destination_id = dst_app_id; | ||
| 528 | param.sender_id = src_app_id; | ||
| 529 | param.object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 530 | param.signal = signal_type; | ||
| 531 | param.buffer.resize(buffer_size); | ||
| 532 | Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); | ||
| 533 | |||
| 534 | SendParameter(param); | ||
| 535 | |||
| 536 | // If the applet is running in HLE mode, use the HLE interface to communicate with it. | ||
| 537 | if (auto dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id))) { | ||
| 538 | rb.Push(dest_applet->ReceiveParameter(param)); | ||
| 539 | } else { | ||
| 540 | rb.Push(RESULT_SUCCESS); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | void ReceiveParameter(Service::Interface* self) { | ||
| 545 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080 | ||
| 546 | u32 app_id = rp.Pop<u32>(); | ||
| 547 | u32 buffer_size = rp.Pop<u32>(); | ||
| 548 | |||
| 549 | size_t static_buff_size; | ||
| 550 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 551 | if (buffer_size > static_buff_size) | ||
| 552 | LOG_WARNING( | ||
| 553 | Service_APT, | ||
| 554 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 555 | buffer_size, static_buff_size); | ||
| 556 | |||
| 557 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); | ||
| 558 | |||
| 559 | if (!next_parameter) { | ||
| 560 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 561 | rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, | ||
| 562 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 563 | return; | ||
| 564 | } | ||
| 565 | |||
| 566 | if (next_parameter->destination_id != app_id) { | ||
| 567 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 568 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||
| 569 | ErrorLevel::Status)); | ||
| 570 | return; | ||
| 571 | } | ||
| 572 | |||
| 573 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||
| 574 | |||
| 575 | rb.Push(RESULT_SUCCESS); // No error | ||
| 576 | rb.Push(next_parameter->sender_id); | ||
| 577 | rb.Push(next_parameter->signal); // Signal type | ||
| 578 | ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||
| 579 | rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size | ||
| 580 | |||
| 581 | rb.PushMoveHandles((next_parameter->object != nullptr) | ||
| 582 | ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap() | ||
| 583 | : 0); | ||
| 584 | |||
| 585 | rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); | ||
| 586 | |||
| 587 | Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); | ||
| 588 | |||
| 589 | // Clear the parameter | ||
| 590 | next_parameter = boost::none; | ||
| 591 | } | ||
| 592 | |||
| 593 | void GlanceParameter(Service::Interface* self) { | ||
| 594 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080 | ||
| 595 | u32 app_id = rp.Pop<u32>(); | ||
| 596 | u32 buffer_size = rp.Pop<u32>(); | ||
| 597 | |||
| 598 | size_t static_buff_size; | ||
| 599 | VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 600 | if (buffer_size > static_buff_size) | ||
| 601 | LOG_WARNING( | ||
| 602 | Service_APT, | ||
| 603 | "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 604 | buffer_size, static_buff_size); | ||
| 605 | |||
| 606 | LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); | ||
| 607 | |||
| 608 | if (!next_parameter) { | ||
| 609 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 610 | rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, | ||
| 611 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | |||
| 615 | if (next_parameter->destination_id != app_id) { | ||
| 616 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 617 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||
| 618 | ErrorLevel::Status)); | ||
| 619 | return; | ||
| 620 | } | ||
| 621 | |||
| 622 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); | ||
| 623 | rb.Push(RESULT_SUCCESS); // No error | ||
| 624 | rb.Push(next_parameter->sender_id); | ||
| 625 | rb.Push(next_parameter->signal); // Signal type | ||
| 626 | ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); | ||
| 627 | rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size | ||
| 628 | |||
| 629 | rb.PushMoveHandles((next_parameter->object != nullptr) | ||
| 630 | ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap() | ||
| 631 | : 0); | ||
| 632 | |||
| 633 | rb.PushStaticBuffer(buffer, next_parameter->buffer.size(), 0); | ||
| 634 | |||
| 635 | Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); | ||
| 636 | |||
| 637 | // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. | ||
| 638 | if (next_parameter->signal == static_cast<u32>(SignalType::DspSleep) || | ||
| 639 | next_parameter->signal == static_cast<u32>(SignalType::DspWakeup)) | ||
| 640 | next_parameter = boost::none; | ||
| 641 | } | ||
| 642 | |||
| 643 | void CancelParameter(Service::Interface* self) { | ||
| 644 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100 | ||
| 645 | |||
| 646 | bool check_sender = rp.Pop<bool>(); | ||
| 647 | u32 sender_appid = rp.Pop<u32>(); | ||
| 648 | bool check_receiver = rp.Pop<bool>(); | ||
| 649 | u32 receiver_appid = rp.Pop<u32>(); | ||
| 650 | |||
| 651 | bool cancellation_success = true; | ||
| 652 | |||
| 653 | if (!next_parameter) { | ||
| 654 | cancellation_success = false; | ||
| 655 | } else { | ||
| 656 | if (check_sender && next_parameter->sender_id != sender_appid) | ||
| 657 | cancellation_success = false; | ||
| 658 | |||
| 659 | if (check_receiver && next_parameter->destination_id != receiver_appid) | ||
| 660 | cancellation_success = false; | ||
| 661 | } | ||
| 662 | |||
| 663 | if (cancellation_success) | ||
| 664 | next_parameter = boost::none; | ||
| 665 | |||
| 666 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 667 | |||
| 668 | rb.Push(RESULT_SUCCESS); // No error | ||
| 669 | rb.Push(cancellation_success); | ||
| 670 | |||
| 671 | LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, " | ||
| 672 | "check_receiver=%u, receiver_appid=0x%08X", | ||
| 673 | check_sender, sender_appid, check_receiver, receiver_appid); | ||
| 674 | } | ||
| 675 | |||
| 676 | void PrepareToStartApplication(Service::Interface* self) { | ||
| 677 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x15, 5, 0); // 0x00150140 | ||
| 678 | u32 title_info1 = rp.Pop<u32>(); | ||
| 679 | u32 title_info2 = rp.Pop<u32>(); | ||
| 680 | u32 title_info3 = rp.Pop<u32>(); | ||
| 681 | u32 title_info4 = rp.Pop<u32>(); | ||
| 682 | u32 flags = rp.Pop<u32>(); | ||
| 683 | |||
| 684 | if (flags & 0x00000100) { | ||
| 685 | unknown_ns_state_field = 1; | ||
| 686 | } | ||
| 687 | |||
| 688 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 689 | rb.Push(RESULT_SUCCESS); // No error | ||
| 690 | |||
| 691 | LOG_WARNING(Service_APT, | ||
| 692 | "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X," | ||
| 693 | "title_info4=0x%08X, flags=0x%08X", | ||
| 694 | title_info1, title_info2, title_info3, title_info4, flags); | ||
| 695 | } | ||
| 696 | |||
| 697 | void StartApplication(Service::Interface* self) { | ||
| 698 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 3, 4); // 0x001B00C4 | ||
| 699 | u32 buffer1_size = rp.Pop<u32>(); | ||
| 700 | u32 buffer2_size = rp.Pop<u32>(); | ||
| 701 | u32 flag = rp.Pop<u32>(); | ||
| 702 | size_t size1; | ||
| 703 | VAddr buffer1_ptr = rp.PopStaticBuffer(&size1); | ||
| 704 | size_t size2; | ||
| 705 | VAddr buffer2_ptr = rp.PopStaticBuffer(&size2); | ||
| 706 | |||
| 707 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 708 | rb.Push(RESULT_SUCCESS); // No error | ||
| 709 | |||
| 710 | LOG_WARNING(Service_APT, | ||
| 711 | "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X," | ||
| 712 | "size1=0x%08zX, buffer1_ptr=0x%08X, size2=0x%08zX, buffer2_ptr=0x%08X", | ||
| 713 | buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr); | ||
| 714 | } | ||
| 715 | |||
| 716 | void AppletUtility(Service::Interface* self) { | ||
| 717 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4B, 3, 2); // 0x004B00C2 | ||
| 718 | |||
| 719 | // These are from 3dbrew - I'm not really sure what they're used for. | ||
| 720 | u32 utility_command = rp.Pop<u32>(); | ||
| 721 | u32 input_size = rp.Pop<u32>(); | ||
| 722 | u32 output_size = rp.Pop<u32>(); | ||
| 723 | VAddr input_addr = rp.PopStaticBuffer(); | ||
| 724 | |||
| 725 | VAddr output_addr = rp.PeekStaticBuffer(0); | ||
| 726 | |||
| 727 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 728 | rb.Push(RESULT_SUCCESS); // No error | ||
| 729 | |||
| 730 | LOG_WARNING(Service_APT, | ||
| 731 | "(STUBBED) called command=0x%08X, input_size=0x%08X, output_size=0x%08X, " | ||
| 732 | "input_addr=0x%08X, output_addr=0x%08X", | ||
| 733 | utility_command, input_size, output_size, input_addr, output_addr); | ||
| 734 | } | ||
| 735 | |||
| 736 | void SetAppCpuTimeLimit(Service::Interface* self) { | ||
| 737 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4F, 2, 0); // 0x4F0080 | ||
| 738 | u32 value = rp.Pop<u32>(); | ||
| 739 | cpu_percent = rp.Pop<u32>(); | ||
| 740 | |||
| 741 | if (value != 1) { | ||
| 742 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | ||
| 743 | } | ||
| 744 | |||
| 745 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 746 | rb.Push(RESULT_SUCCESS); // No error | ||
| 747 | |||
| 748 | LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value); | ||
| 749 | } | ||
| 750 | |||
| 751 | void GetAppCpuTimeLimit(Service::Interface* self) { | ||
| 752 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x50, 1, 0); // 0x500040 | ||
| 753 | u32 value = rp.Pop<u32>(); | ||
| 754 | |||
| 755 | if (value != 1) { | ||
| 756 | LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); | ||
| 757 | } | ||
| 758 | |||
| 759 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 760 | rb.Push(RESULT_SUCCESS); // No error | ||
| 761 | rb.Push(cpu_percent); | ||
| 762 | |||
| 763 | LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); | ||
| 764 | } | ||
| 765 | |||
| 766 | void PrepareToStartLibraryApplet(Service::Interface* self) { | ||
| 767 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 1, 0); // 0x180040 | ||
| 768 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||
| 769 | |||
| 770 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||
| 771 | |||
| 772 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 773 | |||
| 774 | // TODO(Subv): Launch the requested applet application. | ||
| 775 | |||
| 776 | auto applet = HLE::Applets::Applet::Get(applet_id); | ||
| 777 | if (applet) { | ||
| 778 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | ||
| 779 | rb.Push(RESULT_SUCCESS); | ||
| 780 | } else { | ||
| 781 | rb.Push(HLE::Applets::Applet::Create(applet_id)); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 785 | void PrepareToStartNewestHomeMenu(Service::Interface* self) { | ||
| 786 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 0, 0); // 0x1A0000 | ||
| 787 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 788 | |||
| 789 | // TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise). | ||
| 790 | |||
| 791 | // This command must return an error when called, otherwise the Home Menu will try to reboot the | ||
| 792 | // system. | ||
| 793 | rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, | ||
| 794 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 795 | |||
| 796 | LOG_DEBUG(Service_APT, "called"); | ||
| 797 | } | ||
| 798 | |||
| 799 | void PreloadLibraryApplet(Service::Interface* self) { | ||
| 800 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x16, 1, 0); // 0x160040 | ||
| 801 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||
| 802 | |||
| 803 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||
| 804 | |||
| 805 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 806 | |||
| 807 | // TODO(Subv): Launch the requested applet application. | ||
| 808 | |||
| 809 | auto applet = HLE::Applets::Applet::Get(applet_id); | ||
| 810 | if (applet) { | ||
| 811 | LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id); | ||
| 812 | rb.Push(RESULT_SUCCESS); | ||
| 813 | } else { | ||
| 814 | rb.Push(HLE::Applets::Applet::Create(applet_id)); | ||
| 815 | } | ||
| 816 | } | ||
| 817 | |||
| 818 | void StartLibraryApplet(Service::Interface* self) { | ||
| 819 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 2, 4); // 0x1E0084 | ||
| 820 | AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>()); | ||
| 821 | |||
| 822 | size_t buffer_size = rp.Pop<u32>(); | ||
| 823 | Kernel::Handle handle = rp.PopHandle(); | ||
| 824 | VAddr buffer_addr = rp.PopStaticBuffer(); | ||
| 825 | |||
| 826 | LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id); | ||
| 827 | |||
| 828 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 829 | |||
| 830 | // Send the Wakeup signal to the applet | ||
| 831 | MessageParameter param; | ||
| 832 | param.destination_id = static_cast<u32>(applet_id); | ||
| 833 | param.sender_id = static_cast<u32>(AppletId::Application); | ||
| 834 | param.object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 835 | param.signal = static_cast<u32>(SignalType::Wakeup); | ||
| 836 | param.buffer.resize(buffer_size); | ||
| 837 | Memory::ReadBlock(buffer_addr, param.buffer.data(), param.buffer.size()); | ||
| 838 | SendParameter(param); | ||
| 839 | |||
| 840 | // In case the applet is being HLEd, attempt to communicate with it. | ||
| 841 | if (auto applet = HLE::Applets::Applet::Get(applet_id)) { | ||
| 842 | AppletStartupParameter parameter; | ||
| 843 | parameter.object = Kernel::g_handle_table.GetGeneric(handle); | ||
| 844 | parameter.buffer.resize(buffer_size); | ||
| 845 | Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); | ||
| 846 | rb.Push(applet->Start(parameter)); | ||
| 847 | } else { | ||
| 848 | rb.Push(RESULT_SUCCESS); | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | void CancelLibraryApplet(Service::Interface* self) { | ||
| 853 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3B, 1, 0); // 0x003B0040 | ||
| 854 | bool exiting = rp.Pop<bool>(); | ||
| 855 | |||
| 856 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 857 | rb.Push<u32>(1); // TODO: Find the return code meaning | ||
| 858 | |||
| 859 | LOG_WARNING(Service_APT, "(STUBBED) called exiting=%d", exiting); | ||
| 860 | } | ||
| 861 | |||
| 862 | void SetScreenCapPostPermission(Service::Interface* self) { | ||
| 863 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x55, 1, 0); // 0x00550040 | ||
| 864 | |||
| 865 | screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); | ||
| 866 | |||
| 867 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 868 | rb.Push(RESULT_SUCCESS); // No error | ||
| 869 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | ||
| 870 | screen_capture_post_permission); | ||
| 871 | } | ||
| 872 | |||
| 873 | void GetScreenCapPostPermission(Service::Interface* self) { | ||
| 874 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x56, 0, 0); // 0x00560000 | ||
| 875 | |||
| 876 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 877 | rb.Push(RESULT_SUCCESS); // No error | ||
| 878 | rb.Push(static_cast<u32>(screen_capture_post_permission)); | ||
| 879 | LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", | ||
| 880 | screen_capture_post_permission); | ||
| 881 | } | ||
| 882 | |||
| 883 | void GetAppletInfo(Service::Interface* self) { | ||
| 884 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 1, 0); // 0x60040 | ||
| 885 | auto app_id = static_cast<AppletId>(rp.Pop<u32>()); | ||
| 886 | |||
| 887 | if (auto applet = HLE::Applets::Applet::Get(app_id)) { | ||
| 888 | // TODO(Subv): Get the title id for the current applet and write it in the response[2-3] | ||
| 889 | IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); | ||
| 890 | rb.Push(RESULT_SUCCESS); | ||
| 891 | u64 title_id = 0; | ||
| 892 | rb.Push(title_id); | ||
| 893 | rb.Push(static_cast<u32>(Service::FS::MediaType::NAND)); | ||
| 894 | rb.Push(true); // Registered | ||
| 895 | rb.Push(true); // Loaded | ||
| 896 | rb.Push<u32>(0); // Applet Attributes | ||
| 897 | } else { | ||
| 898 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 899 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, | ||
| 900 | ErrorLevel::Status)); | ||
| 901 | } | ||
| 902 | LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id); | ||
| 903 | } | ||
| 904 | |||
| 905 | void GetStartupArgument(Service::Interface* self) { | ||
| 906 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x51, 2, 0); // 0x00510080 | ||
| 907 | u32 parameter_size = rp.Pop<u32>(); | ||
| 908 | StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>()); | ||
| 909 | |||
| 910 | if (parameter_size >= 0x300) { | ||
| 911 | LOG_ERROR( | ||
| 912 | Service_APT, | ||
| 913 | "Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x", | ||
| 914 | parameter_size); | ||
| 915 | return; | ||
| 916 | } | ||
| 917 | |||
| 918 | size_t static_buff_size; | ||
| 919 | VAddr addr = rp.PeekStaticBuffer(0, &static_buff_size); | ||
| 920 | if (parameter_size > static_buff_size) | ||
| 921 | LOG_WARNING( | ||
| 922 | Service_APT, | ||
| 923 | "parameter_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", | ||
| 924 | parameter_size, static_buff_size); | ||
| 925 | |||
| 926 | if (addr && parameter_size) { | ||
| 927 | Memory::ZeroBlock(addr, parameter_size); | ||
| 928 | } | ||
| 929 | |||
| 930 | LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x", | ||
| 931 | startup_argument_type, parameter_size); | ||
| 932 | |||
| 933 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||
| 934 | rb.Push(RESULT_SUCCESS); | ||
| 935 | rb.Push<u32>(0); | ||
| 936 | rb.PushStaticBuffer(addr, parameter_size, 0); | ||
| 937 | } | ||
| 938 | |||
| 939 | void Wrap(Service::Interface* self) { | ||
| 940 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x46, 4, 4); | ||
| 941 | const u32 output_size = rp.Pop<u32>(); | ||
| 942 | const u32 input_size = rp.Pop<u32>(); | ||
| 943 | const u32 nonce_offset = rp.Pop<u32>(); | ||
| 944 | u32 nonce_size = rp.Pop<u32>(); | ||
| 945 | size_t desc_size; | ||
| 946 | IPC::MappedBufferPermissions desc_permission; | ||
| 947 | const VAddr input = rp.PopMappedBuffer(&desc_size, &desc_permission); | ||
| 948 | ASSERT(desc_size == input_size && desc_permission == IPC::MappedBufferPermissions::R); | ||
| 949 | const VAddr output = rp.PopMappedBuffer(&desc_size, &desc_permission); | ||
| 950 | ASSERT(desc_size == output_size && desc_permission == IPC::MappedBufferPermissions::W); | ||
| 951 | |||
| 952 | // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't | ||
| 953 | // check the buffer size and writes data with potential overflow. | ||
| 954 | ASSERT_MSG(output_size == input_size + HW::AES::CCM_MAC_SIZE, | ||
| 955 | "input_size (%d) doesn't match to output_size (%d)", input_size, output_size); | ||
| 956 | |||
| 957 | LOG_DEBUG(Service_APT, "called, output_size=%u, input_size=%u, nonce_offset=%u, nonce_size=%u", | ||
| 958 | output_size, input_size, nonce_offset, nonce_size); | ||
| 959 | |||
| 960 | // Note: This weird nonce size modification is verified against real 3DS | ||
| 961 | nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); | ||
| 962 | |||
| 963 | // Reads nonce and concatenates the rest of the input as plaintext | ||
| 964 | HW::AES::CCMNonce nonce{}; | ||
| 965 | Memory::ReadBlock(input + nonce_offset, nonce.data(), nonce_size); | ||
| 966 | u32 pdata_size = input_size - nonce_size; | ||
| 967 | std::vector<u8> pdata(pdata_size); | ||
| 968 | Memory::ReadBlock(input, pdata.data(), nonce_offset); | ||
| 969 | Memory::ReadBlock(input + nonce_offset + nonce_size, pdata.data() + nonce_offset, | ||
| 970 | pdata_size - nonce_offset); | ||
| 971 | |||
| 972 | // Encrypts the plaintext using AES-CCM | ||
| 973 | auto cipher = HW::AES::EncryptSignCCM(pdata, nonce, HW::AES::KeySlotID::APTWrap); | ||
| 974 | |||
| 975 | // Puts the nonce to the beginning of the output, with ciphertext followed | ||
| 976 | Memory::WriteBlock(output, nonce.data(), nonce_size); | ||
| 977 | Memory::WriteBlock(output + nonce_size, cipher.data(), cipher.size()); | ||
| 978 | |||
| 979 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); | ||
| 980 | rb.Push(RESULT_SUCCESS); | ||
| 981 | |||
| 982 | // Unmap buffer | ||
| 983 | rb.PushMappedBuffer(input, input_size, IPC::MappedBufferPermissions::R); | ||
| 984 | rb.PushMappedBuffer(output, output_size, IPC::MappedBufferPermissions::W); | ||
| 985 | } | ||
| 986 | |||
| 987 | void Unwrap(Service::Interface* self) { | ||
| 988 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x47, 4, 4); | ||
| 989 | const u32 output_size = rp.Pop<u32>(); | ||
| 990 | const u32 input_size = rp.Pop<u32>(); | ||
| 991 | const u32 nonce_offset = rp.Pop<u32>(); | ||
| 992 | u32 nonce_size = rp.Pop<u32>(); | ||
| 993 | size_t desc_size; | ||
| 994 | IPC::MappedBufferPermissions desc_permission; | ||
| 995 | const VAddr input = rp.PopMappedBuffer(&desc_size, &desc_permission); | ||
| 996 | ASSERT(desc_size == input_size && desc_permission == IPC::MappedBufferPermissions::R); | ||
| 997 | const VAddr output = rp.PopMappedBuffer(&desc_size, &desc_permission); | ||
| 998 | ASSERT(desc_size == output_size && desc_permission == IPC::MappedBufferPermissions::W); | ||
| 999 | |||
| 1000 | // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't | ||
| 1001 | // check the buffer size and writes data with potential overflow. | ||
| 1002 | ASSERT_MSG(output_size == input_size - HW::AES::CCM_MAC_SIZE, | ||
| 1003 | "input_size (%d) doesn't match to output_size (%d)", input_size, output_size); | ||
| 1004 | |||
| 1005 | LOG_DEBUG(Service_APT, "called, output_size=%u, input_size=%u, nonce_offset=%u, nonce_size=%u", | ||
| 1006 | output_size, input_size, nonce_offset, nonce_size); | ||
| 1007 | |||
| 1008 | // Note: This weird nonce size modification is verified against real 3DS | ||
| 1009 | nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); | ||
| 1010 | |||
| 1011 | // Reads nonce and cipher text | ||
| 1012 | HW::AES::CCMNonce nonce{}; | ||
| 1013 | Memory::ReadBlock(input, nonce.data(), nonce_size); | ||
| 1014 | u32 cipher_size = input_size - nonce_size; | ||
| 1015 | std::vector<u8> cipher(cipher_size); | ||
| 1016 | Memory::ReadBlock(input + nonce_size, cipher.data(), cipher_size); | ||
| 1017 | |||
| 1018 | // Decrypts the ciphertext using AES-CCM | ||
| 1019 | auto pdata = HW::AES::DecryptVerifyCCM(cipher, nonce, HW::AES::KeySlotID::APTWrap); | ||
| 1020 | |||
| 1021 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); | ||
| 1022 | if (!pdata.empty()) { | ||
| 1023 | // Splits the plaintext and put the nonce in between | ||
| 1024 | Memory::WriteBlock(output, pdata.data(), nonce_offset); | ||
| 1025 | Memory::WriteBlock(output + nonce_offset, nonce.data(), nonce_size); | ||
| 1026 | Memory::WriteBlock(output + nonce_offset + nonce_size, pdata.data() + nonce_offset, | ||
| 1027 | pdata.size() - nonce_offset); | ||
| 1028 | rb.Push(RESULT_SUCCESS); | ||
| 1029 | } else { | ||
| 1030 | LOG_ERROR(Service_APT, "Failed to decrypt data"); | ||
| 1031 | rb.Push(ResultCode(static_cast<ErrorDescription>(1), ErrorModule::PS, | ||
| 1032 | ErrorSummary::WrongArgument, ErrorLevel::Status)); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | // Unmap buffer | ||
| 1036 | rb.PushMappedBuffer(input, input_size, IPC::MappedBufferPermissions::R); | ||
| 1037 | rb.PushMappedBuffer(output, output_size, IPC::MappedBufferPermissions::W); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | void CheckNew3DSApp(Service::Interface* self) { | ||
| 1041 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x101, 0, 0); // 0x01010000 | ||
| 1042 | |||
| 1043 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 1044 | if (unknown_ns_state_field) { | ||
| 1045 | rb.Push(RESULT_SUCCESS); | ||
| 1046 | rb.Push<u32>(0); | ||
| 1047 | } else { | ||
| 1048 | PTM::CheckNew3DS(rb); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | LOG_WARNING(Service_APT, "(STUBBED) called"); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | void CheckNew3DS(Service::Interface* self) { | ||
| 1055 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x102, 0, 0); // 0x01020000 | ||
| 1056 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 1057 | |||
| 1058 | PTM::CheckNew3DS(rb); | ||
| 1059 | |||
| 1060 | LOG_WARNING(Service_APT, "(STUBBED) called"); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | void Init() { | ||
| 1064 | AddService(new APT_A_Interface); | ||
| 1065 | AddService(new APT_S_Interface); | ||
| 1066 | AddService(new APT_U_Interface); | ||
| 1067 | |||
| 1068 | HLE::Applets::Init(); | ||
| 1069 | |||
| 1070 | using Kernel::MemoryPermission; | ||
| 1071 | shared_font_mem = | ||
| 1072 | Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB | ||
| 1073 | MemoryPermission::ReadWrite, MemoryPermission::Read, 0, | ||
| 1074 | Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); | ||
| 1075 | |||
| 1076 | if (LoadSharedFont()) { | ||
| 1077 | shared_font_loaded = true; | ||
| 1078 | } else if (LoadLegacySharedFont()) { | ||
| 1079 | LOG_WARNING(Service_APT, "Loaded shared font by legacy method"); | ||
| 1080 | shared_font_loaded = true; | ||
| 1081 | } else { | ||
| 1082 | LOG_WARNING(Service_APT, "Unable to load shared font"); | ||
| 1083 | shared_font_loaded = false; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | lock = Kernel::Mutex::Create(false, 0, "APT_U:Lock"); | ||
| 1087 | |||
| 1088 | cpu_percent = 0; | ||
| 1089 | unknown_ns_state_field = 0; | ||
| 1090 | screen_capture_post_permission = | ||
| 1091 | ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value | ||
| 1092 | |||
| 1093 | for (size_t slot = 0; slot < applet_slots.size(); ++slot) { | ||
| 1094 | auto& slot_data = applet_slots[slot]; | ||
| 1095 | slot_data.slot = static_cast<AppletSlot>(slot); | ||
| 1096 | slot_data.applet_id = AppletId::None; | ||
| 1097 | slot_data.attributes.raw = 0; | ||
| 1098 | slot_data.registered = false; | ||
| 1099 | slot_data.notification_event = | ||
| 1100 | Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); | ||
| 1101 | slot_data.parameter_event = | ||
| 1102 | Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); | ||
| 1103 | } | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | void Shutdown() { | ||
| 1107 | shared_font_mem = nullptr; | ||
| 1108 | shared_font_loaded = false; | ||
| 1109 | shared_font_relocated = false; | ||
| 1110 | lock = nullptr; | ||
| 1111 | |||
| 1112 | for (auto& slot : applet_slots) { | ||
| 1113 | slot.registered = false; | ||
| 1114 | slot.notification_event = nullptr; | ||
| 1115 | slot.parameter_event = nullptr; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | next_parameter = boost::none; | ||
| 1119 | |||
| 1120 | HLE::Applets::Shutdown(); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | } // namespace APT | ||
| 1124 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h deleted file mode 100644 index 7b79e1f3e..000000000 --- a/src/core/hle/service/apt/apt.h +++ /dev/null | |||
| @@ -1,533 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | |||
| 15 | class Interface; | ||
| 16 | |||
| 17 | namespace APT { | ||
| 18 | |||
| 19 | /// Each APT service can only have up to 2 sessions connected at the same time. | ||
| 20 | static const u32 MaxAPTSessions = 2; | ||
| 21 | |||
| 22 | /// Holds information about the parameters used in Send/Glance/ReceiveParameter | ||
| 23 | struct MessageParameter { | ||
| 24 | u32 sender_id = 0; | ||
| 25 | u32 destination_id = 0; | ||
| 26 | u32 signal = 0; | ||
| 27 | Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||
| 28 | std::vector<u8> buffer; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// Holds information about the parameters used in StartLibraryApplet | ||
| 32 | struct AppletStartupParameter { | ||
| 33 | Kernel::SharedPtr<Kernel::Object> object = nullptr; | ||
| 34 | std::vector<u8> buffer; | ||
| 35 | }; | ||
| 36 | |||
| 37 | /// Used by the application to pass information about the current framebuffer to applets. | ||
| 38 | struct CaptureBufferInfo { | ||
| 39 | u32_le size; | ||
| 40 | u8 is_3d; | ||
| 41 | INSERT_PADDING_BYTES(0x3); // Padding for alignment | ||
| 42 | u32_le top_screen_left_offset; | ||
| 43 | u32_le top_screen_right_offset; | ||
| 44 | u32_le top_screen_format; | ||
| 45 | u32_le bottom_screen_left_offset; | ||
| 46 | u32_le bottom_screen_right_offset; | ||
| 47 | u32_le bottom_screen_format; | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has incorrect size"); | ||
| 50 | |||
| 51 | /// Signals used by APT functions | ||
| 52 | enum class SignalType : u32 { | ||
| 53 | None = 0x0, | ||
| 54 | Wakeup = 0x1, | ||
| 55 | Request = 0x2, | ||
| 56 | Response = 0x3, | ||
| 57 | Exit = 0x4, | ||
| 58 | Message = 0x5, | ||
| 59 | HomeButtonSingle = 0x6, | ||
| 60 | HomeButtonDouble = 0x7, | ||
| 61 | DspSleep = 0x8, | ||
| 62 | DspWakeup = 0x9, | ||
| 63 | WakeupByExit = 0xA, | ||
| 64 | WakeupByPause = 0xB, | ||
| 65 | WakeupByCancel = 0xC, | ||
| 66 | WakeupByCancelAll = 0xD, | ||
| 67 | WakeupByPowerButtonClick = 0xE, | ||
| 68 | WakeupToJumpHome = 0xF, | ||
| 69 | RequestForSysApplet = 0x10, | ||
| 70 | WakeupToLaunchApplication = 0x11, | ||
| 71 | }; | ||
| 72 | |||
| 73 | /// App Id's used by APT functions | ||
| 74 | enum class AppletId : u32 { | ||
| 75 | None = 0, | ||
| 76 | AnySystemApplet = 0x100, | ||
| 77 | HomeMenu = 0x101, | ||
| 78 | AlternateMenu = 0x103, | ||
| 79 | Camera = 0x110, | ||
| 80 | FriendsList = 0x112, | ||
| 81 | GameNotes = 0x113, | ||
| 82 | InternetBrowser = 0x114, | ||
| 83 | InstructionManual = 0x115, | ||
| 84 | Notifications = 0x116, | ||
| 85 | Miiverse = 0x117, | ||
| 86 | MiiversePost = 0x118, | ||
| 87 | AmiiboSettings = 0x119, | ||
| 88 | AnySysLibraryApplet = 0x200, | ||
| 89 | SoftwareKeyboard1 = 0x201, | ||
| 90 | Ed1 = 0x202, | ||
| 91 | PnoteApp = 0x204, | ||
| 92 | SnoteApp = 0x205, | ||
| 93 | Error = 0x206, | ||
| 94 | Mint = 0x207, | ||
| 95 | Extrapad = 0x208, | ||
| 96 | Memolib = 0x209, | ||
| 97 | Application = 0x300, | ||
| 98 | AnyLibraryApplet = 0x400, | ||
| 99 | SoftwareKeyboard2 = 0x401, | ||
| 100 | Ed2 = 0x402, | ||
| 101 | PnoteApp2 = 0x404, | ||
| 102 | SnoteApp2 = 0x405, | ||
| 103 | Error2 = 0x406, | ||
| 104 | Mint2 = 0x407, | ||
| 105 | Extrapad2 = 0x408, | ||
| 106 | Memolib2 = 0x409, | ||
| 107 | }; | ||
| 108 | |||
| 109 | enum class StartupArgumentType : u32 { | ||
| 110 | OtherApp = 0, | ||
| 111 | Restart = 1, | ||
| 112 | OtherMedia = 2, | ||
| 113 | }; | ||
| 114 | |||
| 115 | enum class ScreencapPostPermission : u32 { | ||
| 116 | CleanThePermission = 0, // TODO(JamePeng): verify what "zero" means | ||
| 117 | NoExplicitSetting = 1, | ||
| 118 | EnableScreenshotPostingToMiiverse = 2, | ||
| 119 | DisableScreenshotPostingToMiiverse = 3 | ||
| 120 | }; | ||
| 121 | |||
| 122 | namespace ErrCodes { | ||
| 123 | enum { | ||
| 124 | ParameterPresent = 2, | ||
| 125 | InvalidAppletSlot = 4, | ||
| 126 | }; | ||
| 127 | } // namespace ErrCodes | ||
| 128 | |||
| 129 | /// Send a parameter to the currently-running application, which will read it via ReceiveParameter | ||
| 130 | void SendParameter(const MessageParameter& parameter); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * APT::Initialize service function | ||
| 134 | * Service function that initializes the APT process for the running application | ||
| 135 | * Outputs: | ||
| 136 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 137 | * 3 : Handle to the notification event | ||
| 138 | * 4 : Handle to the pause event | ||
| 139 | */ | ||
| 140 | void Initialize(Service::Interface* self); | ||
| 141 | |||
| 142 | /** | ||
| 143 | * APT::GetSharedFont service function | ||
| 144 | * Outputs: | ||
| 145 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 146 | * 2 : Virtual address of where shared font will be loaded in memory | ||
| 147 | * 4 : Handle to shared font memory | ||
| 148 | */ | ||
| 149 | void GetSharedFont(Service::Interface* self); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * APT::Wrap service function | ||
| 153 | * Inputs: | ||
| 154 | * 1 : Output buffer size | ||
| 155 | * 2 : Input buffer size | ||
| 156 | * 3 : Nonce offset to the input buffer | ||
| 157 | * 4 : Nonce size | ||
| 158 | * 5 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xA) | ||
| 159 | * 6 : Input buffer address | ||
| 160 | * 7 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xC) | ||
| 161 | * 8 : Output buffer address | ||
| 162 | * Outputs: | ||
| 163 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 164 | * 2 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xA) | ||
| 165 | * 3 : Input buffer address | ||
| 166 | * 4 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xC) | ||
| 167 | * 5 : Output buffer address | ||
| 168 | */ | ||
| 169 | void Wrap(Service::Interface* self); | ||
| 170 | |||
| 171 | /** | ||
| 172 | * APT::Unwrap service function | ||
| 173 | * Inputs: | ||
| 174 | * 1 : Output buffer size | ||
| 175 | * 2 : Input buffer size | ||
| 176 | * 3 : Nonce offset to the output buffer | ||
| 177 | * 4 : Nonce size | ||
| 178 | * 5 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xA) | ||
| 179 | * 6 : Input buffer address | ||
| 180 | * 7 : Buffer mapping descriptor ((input_buffer_size << 4) | 0xC) | ||
| 181 | * 8 : Output buffer address | ||
| 182 | * Outputs: | ||
| 183 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 184 | * 2 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xA) | ||
| 185 | * 3 : Input buffer address | ||
| 186 | * 4 : Buffer unmapping descriptor ((input_buffer_size << 4) | 0xC) | ||
| 187 | * 5 : Output buffer address | ||
| 188 | */ | ||
| 189 | void Unwrap(Service::Interface* self); | ||
| 190 | |||
| 191 | /** | ||
| 192 | * APT::NotifyToWait service function | ||
| 193 | * Inputs: | ||
| 194 | * 1 : AppID | ||
| 195 | * Outputs: | ||
| 196 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 197 | */ | ||
| 198 | void NotifyToWait(Service::Interface* self); | ||
| 199 | |||
| 200 | /** | ||
| 201 | * APT::GetLockHandle service function | ||
| 202 | * Inputs: | ||
| 203 | * 1 : Applet attributes | ||
| 204 | * Outputs: | ||
| 205 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 206 | * 2 : Applet attributes | ||
| 207 | * 3 : Power button state | ||
| 208 | * 4 : IPC handle descriptor | ||
| 209 | * 5 : APT mutex handle | ||
| 210 | */ | ||
| 211 | void GetLockHandle(Service::Interface* self); | ||
| 212 | |||
| 213 | /** | ||
| 214 | * APT::Enable service function | ||
| 215 | * Inputs: | ||
| 216 | * 1 : Applet attributes | ||
| 217 | * Outputs: | ||
| 218 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 219 | */ | ||
| 220 | void Enable(Service::Interface* self); | ||
| 221 | |||
| 222 | /** | ||
| 223 | * APT::GetAppletManInfo service function. | ||
| 224 | * Inputs: | ||
| 225 | * 1 : Unknown | ||
| 226 | * Outputs: | ||
| 227 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 228 | * 2 : Unknown u32 value | ||
| 229 | * 3 : Unknown u8 value | ||
| 230 | * 4 : Home Menu AppId | ||
| 231 | * 5 : AppID of currently active app | ||
| 232 | */ | ||
| 233 | void GetAppletManInfo(Service::Interface* self); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * APT::GetAppletInfo service function. | ||
| 237 | * Inputs: | ||
| 238 | * 1 : AppId | ||
| 239 | * Outputs: | ||
| 240 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 241 | * 2-3 : Title ID | ||
| 242 | * 4 : Media Type | ||
| 243 | * 5 : Registered | ||
| 244 | * 6 : Loaded | ||
| 245 | * 7 : Attributes | ||
| 246 | */ | ||
| 247 | void GetAppletInfo(Service::Interface* self); | ||
| 248 | |||
| 249 | /** | ||
| 250 | * APT::IsRegistered service function. This returns whether the specified AppID is registered with | ||
| 251 | * NS yet. An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home | ||
| 252 | * Menu uses this command to determine when the launched process is running and to determine when to | ||
| 253 | * stop using GSP, etc., while displaying the "Nintendo 3DS" loading screen. | ||
| 254 | * | ||
| 255 | * Inputs: | ||
| 256 | * 1 : AppID | ||
| 257 | * Outputs: | ||
| 258 | * 0 : Return header | ||
| 259 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 260 | * 2 : Output, 0 = not registered, 1 = registered. | ||
| 261 | */ | ||
| 262 | void IsRegistered(Service::Interface* self); | ||
| 263 | |||
| 264 | void InquireNotification(Service::Interface* self); | ||
| 265 | |||
| 266 | /** | ||
| 267 | * APT::SendParameter service function. This sets the parameter data state. | ||
| 268 | * Inputs: | ||
| 269 | * 1 : Source AppID | ||
| 270 | * 2 : Destination AppID | ||
| 271 | * 3 : Signal type | ||
| 272 | * 4 : Parameter buffer size, max size is 0x1000 (this can be zero) | ||
| 273 | * 5 : Value | ||
| 274 | * 6 : Handle to the destination process, likely used for shared memory (this can be zero) | ||
| 275 | * 7 : (Size<<14) | 2 | ||
| 276 | * 8 : Input parameter buffer ptr | ||
| 277 | * Outputs: | ||
| 278 | * 0 : Return Header | ||
| 279 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 280 | */ | ||
| 281 | void SendParameter(Service::Interface* self); | ||
| 282 | |||
| 283 | /** | ||
| 284 | * APT::ReceiveParameter service function. This returns the current parameter data from NS state, | ||
| 285 | * from the source process which set the parameters. Once finished, NS will clear a flag in the NS | ||
| 286 | * state so that this command will return an error if this command is used again if parameters were | ||
| 287 | * not set again. This is called when the second Initialize event is triggered. It returns a signal | ||
| 288 | * type indicating why it was triggered. | ||
| 289 | * Inputs: | ||
| 290 | * 1 : AppID | ||
| 291 | * 2 : Parameter buffer size, max size is 0x1000 | ||
| 292 | * Outputs: | ||
| 293 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 294 | * 2 : AppID of the process which sent these parameters | ||
| 295 | * 3 : Signal type | ||
| 296 | * 4 : Actual parameter buffer size, this is <= to the the input size | ||
| 297 | * 5 : Value | ||
| 298 | * 6 : Handle from the source process which set the parameters, likely used for shared memory | ||
| 299 | * 7 : Size | ||
| 300 | * 8 : Output parameter buffer ptr | ||
| 301 | */ | ||
| 302 | void ReceiveParameter(Service::Interface* self); | ||
| 303 | |||
| 304 | /** | ||
| 305 | * APT::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter | ||
| 306 | * (except for the word value prior to the output handle), except this will not clear the flag | ||
| 307 | * (except when responseword[3]==8 || responseword[3]==9) in NS state. | ||
| 308 | * Inputs: | ||
| 309 | * 1 : AppID | ||
| 310 | * 2 : Parameter buffer size, max size is 0x1000 | ||
| 311 | * Outputs: | ||
| 312 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 313 | * 2 : Unknown, for now assume AppID of the process which sent these parameters | ||
| 314 | * 3 : Unknown, for now assume Signal type | ||
| 315 | * 4 : Actual parameter buffer size, this is <= to the the input size | ||
| 316 | * 5 : Value | ||
| 317 | * 6 : Handle from the source process which set the parameters, likely used for shared memory | ||
| 318 | * 7 : Size | ||
| 319 | * 8 : Output parameter buffer ptr | ||
| 320 | */ | ||
| 321 | void GlanceParameter(Service::Interface* self); | ||
| 322 | |||
| 323 | /** | ||
| 324 | * APT::CancelParameter service function. When the parameter data is available, and when the above | ||
| 325 | * specified fields match the ones in NS state(for the ones where the checks are enabled), this | ||
| 326 | * clears the flag which indicates that parameter data is available | ||
| 327 | * (same flag cleared by APT:ReceiveParameter). | ||
| 328 | * Inputs: | ||
| 329 | * 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS | ||
| 330 | * state. | ||
| 331 | * 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter. | ||
| 332 | * 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS | ||
| 333 | * state. | ||
| 334 | * 4 : AppID | ||
| 335 | * Outputs: | ||
| 336 | * 0 : Return header | ||
| 337 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 338 | * 2 : Status flag, 0 = failure due to no parameter data being available, or the above enabled | ||
| 339 | * fields don't match the fields in NS state. 1 = success. | ||
| 340 | */ | ||
| 341 | void CancelParameter(Service::Interface* self); | ||
| 342 | |||
| 343 | /** | ||
| 344 | * APT::PrepareToStartApplication service function. When the input title-info programID is zero, | ||
| 345 | * NS will load the actual program ID via AMNet:GetTitleIDList. After doing some checks with the | ||
| 346 | * programID, NS will then set a NS state flag to value 1, then set the programID for AppID | ||
| 347 | * 0x300(application) to the input program ID(or the one from GetTitleIDList). A media-type field | ||
| 348 | * in the NS state is also set to the input media-type value | ||
| 349 | * (other state fields are set at this point as well). With 8.0.0-18, NS will set an u8 NS state | ||
| 350 | * field to value 1 when input flags bit8 is set | ||
| 351 | * Inputs: | ||
| 352 | * 1-4 : 0x10-byte title-info struct | ||
| 353 | * 4 : Flags | ||
| 354 | * Outputs: | ||
| 355 | * 0 : Return header | ||
| 356 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 357 | */ | ||
| 358 | void PrepareToStartApplication(Service::Interface* self); | ||
| 359 | |||
| 360 | /** | ||
| 361 | * APT::StartApplication service function. Buf0 is copied to NS FIRMparams+0x0, then Buf1 is copied | ||
| 362 | * to the NS FIRMparams+0x480. Then the application is launched. | ||
| 363 | * Inputs: | ||
| 364 | * 1 : Buffer 0 size, max size is 0x300 | ||
| 365 | * 2 : Buffer 1 size, max size is 0x20 (this can be zero) | ||
| 366 | * 3 : u8 flag | ||
| 367 | * 4 : (Size0<<14) | 2 | ||
| 368 | * 5 : Buffer 0 pointer | ||
| 369 | * 6 : (Size1<<14) | 0x802 | ||
| 370 | * 7 : Buffer 1 pointer | ||
| 371 | * Outputs: | ||
| 372 | * 0 : Return Header | ||
| 373 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 374 | */ | ||
| 375 | void StartApplication(Service::Interface* self); | ||
| 376 | |||
| 377 | /** | ||
| 378 | * APT::AppletUtility service function | ||
| 379 | * Inputs: | ||
| 380 | * 1 : Unknown, but clearly used for something | ||
| 381 | * 2 : Buffer 1 size (purpose is unknown) | ||
| 382 | * 3 : Buffer 2 size (purpose is unknown) | ||
| 383 | * 5 : Buffer 1 address (purpose is unknown) | ||
| 384 | * 65 : Buffer 2 address (purpose is unknown) | ||
| 385 | * Outputs: | ||
| 386 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 387 | */ | ||
| 388 | void AppletUtility(Service::Interface* self); | ||
| 389 | |||
| 390 | /** | ||
| 391 | * APT::SetAppCpuTimeLimit service function | ||
| 392 | * Inputs: | ||
| 393 | * 1 : Value, must be one | ||
| 394 | * 2 : Percentage of CPU time from 5 to 80 | ||
| 395 | * Outputs: | ||
| 396 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 397 | */ | ||
| 398 | void SetAppCpuTimeLimit(Service::Interface* self); | ||
| 399 | |||
| 400 | /** | ||
| 401 | * APT::GetAppCpuTimeLimit service function | ||
| 402 | * Inputs: | ||
| 403 | * 1 : Value, must be one | ||
| 404 | * Outputs: | ||
| 405 | * 0 : Return header | ||
| 406 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 407 | * 2 : System core CPU time percentage | ||
| 408 | */ | ||
| 409 | void GetAppCpuTimeLimit(Service::Interface* self); | ||
| 410 | |||
| 411 | /** | ||
| 412 | * APT::PrepareToStartLibraryApplet service function | ||
| 413 | * Inputs: | ||
| 414 | * 0 : Command header [0x00180040] | ||
| 415 | * 1 : Id of the applet to start | ||
| 416 | * Outputs: | ||
| 417 | * 0 : Return header | ||
| 418 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 419 | */ | ||
| 420 | void PrepareToStartLibraryApplet(Service::Interface* self); | ||
| 421 | |||
| 422 | /** | ||
| 423 | * APT::PrepareToStartNewestHomeMenu service function | ||
| 424 | * Inputs: | ||
| 425 | * 0 : Command header [0x001A0000] | ||
| 426 | * Outputs: | ||
| 427 | * 0 : Return header | ||
| 428 | * 1 : Result of function | ||
| 429 | */ | ||
| 430 | void PrepareToStartNewestHomeMenu(Service::Interface* self); | ||
| 431 | |||
| 432 | /** | ||
| 433 | * APT::PreloadLibraryApplet service function | ||
| 434 | * Inputs: | ||
| 435 | * 0 : Command header [0x00160040] | ||
| 436 | * 1 : Id of the applet to start | ||
| 437 | * Outputs: | ||
| 438 | * 0 : Return header | ||
| 439 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 440 | */ | ||
| 441 | void PreloadLibraryApplet(Service::Interface* self); | ||
| 442 | |||
| 443 | /** | ||
| 444 | * APT::StartLibraryApplet service function | ||
| 445 | * Inputs: | ||
| 446 | * 0 : Command header [0x001E0084] | ||
| 447 | * 1 : Id of the applet to start | ||
| 448 | * 2 : Buffer size | ||
| 449 | * 3 : Always 0? | ||
| 450 | * 4 : Handle passed to the applet | ||
| 451 | * 5 : (Size << 14) | 2 | ||
| 452 | * 6 : Input buffer virtual address | ||
| 453 | * Outputs: | ||
| 454 | * 0 : Return header | ||
| 455 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 456 | */ | ||
| 457 | void StartLibraryApplet(Service::Interface* self); | ||
| 458 | |||
| 459 | /** | ||
| 460 | * APT::CancelLibraryApplet service function | ||
| 461 | * Inputs: | ||
| 462 | * 0 : Command header [0x003B0040] | ||
| 463 | * 1 : u8, Application exiting (0 = not exiting, 1 = exiting) | ||
| 464 | * Outputs: | ||
| 465 | * 0 : Header code | ||
| 466 | * 1 : Result code | ||
| 467 | */ | ||
| 468 | void CancelLibraryApplet(Service::Interface* self); | ||
| 469 | |||
| 470 | /** | ||
| 471 | * APT::GetStartupArgument service function | ||
| 472 | * Inputs: | ||
| 473 | * 1 : Parameter Size (capped to 0x300) | ||
| 474 | * 2 : StartupArgumentType | ||
| 475 | * 65 : Output buffer for startup argument | ||
| 476 | * Outputs: | ||
| 477 | * 0 : Return header | ||
| 478 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 479 | * 2 : u8, Exists (0 = does not exist, 1 = exists) | ||
| 480 | */ | ||
| 481 | void GetStartupArgument(Service::Interface* self); | ||
| 482 | |||
| 483 | /** | ||
| 484 | * APT::SetScreenCapPostPermission service function | ||
| 485 | * Inputs: | ||
| 486 | * 0 : Header Code[0x00550040] | ||
| 487 | * 1 : u8 The screenshot posting permission | ||
| 488 | * Outputs: | ||
| 489 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 490 | */ | ||
| 491 | void SetScreenCapPostPermission(Service::Interface* self); | ||
| 492 | |||
| 493 | /** | ||
| 494 | * APT::GetScreenCapPostPermission service function | ||
| 495 | * Inputs: | ||
| 496 | * 0 : Header Code[0x00560000] | ||
| 497 | * Outputs: | ||
| 498 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 499 | * 2 : u8 The screenshot posting permission | ||
| 500 | */ | ||
| 501 | void GetScreenCapPostPermission(Service::Interface* self); | ||
| 502 | |||
| 503 | /** | ||
| 504 | * APT::CheckNew3DSApp service function | ||
| 505 | * Outputs: | ||
| 506 | * 1: Result code, 0 on success, otherwise error code | ||
| 507 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. | ||
| 508 | * Note: | ||
| 509 | * This uses PTMSYSM:CheckNew3DS. | ||
| 510 | * When a certain NS state field is non-zero, the output value is zero, | ||
| 511 | * Otherwise the output is from PTMSYSM:CheckNew3DS. | ||
| 512 | * Normally this NS state field is zero, however this state field is set to 1 | ||
| 513 | * when APT:PrepareToStartApplication is used with flags bit8 is set. | ||
| 514 | */ | ||
| 515 | void CheckNew3DSApp(Service::Interface* self); | ||
| 516 | |||
| 517 | /** | ||
| 518 | * Wrapper for PTMSYSM:CheckNew3DS | ||
| 519 | * APT::CheckNew3DS service function | ||
| 520 | * Outputs: | ||
| 521 | * 1: Result code, 0 on success, otherwise error code | ||
| 522 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. | ||
| 523 | */ | ||
| 524 | void CheckNew3DS(Service::Interface* self); | ||
| 525 | |||
| 526 | /// Initialize the APT service | ||
| 527 | void Init(); | ||
| 528 | |||
| 529 | /// Shutdown the APT service | ||
| 530 | void Shutdown(); | ||
| 531 | |||
| 532 | } // namespace APT | ||
| 533 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp deleted file mode 100644 index c496cba8d..000000000 --- a/src/core/hle/service/apt/apt_a.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/apt/apt.h" | ||
| 6 | #include "core/hle/service/apt/apt_a.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace APT { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetLockHandle, "GetLockHandle"}, | ||
| 13 | {0x00020080, Initialize, "Initialize"}, | ||
| 14 | {0x00030040, Enable, "Enable"}, | ||
| 15 | {0x00040040, nullptr, "Finalize"}, | ||
| 16 | {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, | ||
| 17 | {0x00060040, GetAppletInfo, "GetAppletInfo"}, | ||
| 18 | {0x00070000, nullptr, "GetLastSignaledAppletId"}, | ||
| 19 | {0x00080000, nullptr, "CountRegisteredApplet"}, | ||
| 20 | {0x00090040, IsRegistered, "IsRegistered"}, | ||
| 21 | {0x000A0040, nullptr, "GetAttribute"}, | ||
| 22 | {0x000B0040, InquireNotification, "InquireNotification"}, | ||
| 23 | {0x000C0104, SendParameter, "SendParameter"}, | ||
| 24 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, | ||
| 25 | {0x000E0080, GlanceParameter, "GlanceParameter"}, | ||
| 26 | {0x000F0100, CancelParameter, "CancelParameter"}, | ||
| 27 | {0x001000C2, nullptr, "DebugFunc"}, | ||
| 28 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, | ||
| 29 | {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, | ||
| 30 | {0x00130000, nullptr, "GetPreparationState"}, | ||
| 31 | {0x00140040, nullptr, "SetPreparationState"}, | ||
| 32 | {0x00150140, PrepareToStartApplication, "PrepareToStartApplication"}, | ||
| 33 | {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, | ||
| 34 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, | ||
| 35 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, | ||
| 36 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, | ||
| 37 | {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, | ||
| 38 | {0x001B00C4, nullptr, "StartApplication"}, | ||
| 39 | {0x001C0000, nullptr, "WakeupApplication"}, | ||
| 40 | {0x001D0000, nullptr, "CancelApplication"}, | ||
| 41 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, | ||
| 42 | {0x001F0084, nullptr, "StartSystemApplet"}, | ||
| 43 | {0x00200044, nullptr, "StartNewestHomeMenu"}, | ||
| 44 | {0x00210000, nullptr, "OrderToCloseApplication"}, | ||
| 45 | {0x00220040, nullptr, "PrepareToCloseApplication"}, | ||
| 46 | {0x00230040, nullptr, "PrepareToJumpToApplication"}, | ||
| 47 | {0x00240044, nullptr, "JumpToApplication"}, | ||
| 48 | {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, | ||
| 49 | {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, | ||
| 50 | {0x00270044, nullptr, "CloseApplication"}, | ||
| 51 | {0x00280044, nullptr, "CloseLibraryApplet"}, | ||
| 52 | {0x00290044, nullptr, "CloseSystemApplet"}, | ||
| 53 | {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, | ||
| 54 | {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, | ||
| 55 | {0x002C0044, nullptr, "JumpToHomeMenu"}, | ||
| 56 | {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, | ||
| 57 | {0x002E0044, nullptr, "LeaveHomeMenu"}, | ||
| 58 | {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, | ||
| 59 | {0x00300044, nullptr, "LeaveResidentApplet"}, | ||
| 60 | {0x00310100, nullptr, "PrepareToDoApplicationJump"}, | ||
| 61 | {0x00320084, nullptr, "DoApplicationJump"}, | ||
| 62 | {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, | ||
| 63 | {0x00340084, nullptr, "SendDeliverArg"}, | ||
| 64 | {0x00350080, nullptr, "ReceiveDeliverArg"}, | ||
| 65 | {0x00360040, nullptr, "LoadSysMenuArg"}, | ||
| 66 | {0x00370042, nullptr, "StoreSysMenuArg"}, | ||
| 67 | {0x00380040, nullptr, "PreloadResidentApplet"}, | ||
| 68 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, | ||
| 69 | {0x003A0044, nullptr, "StartResidentApplet"}, | ||
| 70 | {0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"}, | ||
| 71 | {0x003C0042, nullptr, "SendDspSleep"}, | ||
| 72 | {0x003D0042, nullptr, "SendDspWakeUp"}, | ||
| 73 | {0x003E0080, nullptr, "ReplySleepQuery"}, | ||
| 74 | {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, | ||
| 75 | {0x00400042, nullptr, "SendCaptureBufferInfo"}, | ||
| 76 | {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, | ||
| 77 | {0x00420080, nullptr, "SleepSystem"}, | ||
| 78 | {0x00430040, NotifyToWait, "NotifyToWait"}, | ||
| 79 | {0x00440000, GetSharedFont, "GetSharedFont"}, | ||
| 80 | {0x00450040, nullptr, "GetWirelessRebootInfo"}, | ||
| 81 | {0x00460104, Wrap, "Wrap"}, | ||
| 82 | {0x00470104, Unwrap, "Unwrap"}, | ||
| 83 | {0x00480100, nullptr, "GetProgramInfo"}, | ||
| 84 | {0x00490180, nullptr, "Reboot"}, | ||
| 85 | {0x004A0040, nullptr, "GetCaptureInfo"}, | ||
| 86 | {0x004B00C2, AppletUtility, "AppletUtility"}, | ||
| 87 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, | ||
| 88 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, | ||
| 89 | {0x004E0000, nullptr, "HardwareResetAsync"}, | ||
| 90 | {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||
| 91 | {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||
| 92 | {0x00510080, GetStartupArgument, "GetStartupArgument"}, | ||
| 93 | {0x00520104, nullptr, "Wrap1"}, | ||
| 94 | {0x00530104, nullptr, "Unwrap1"}, | ||
| 95 | {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||
| 96 | {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||
| 97 | {0x00570044, nullptr, "WakeupApplication2"}, | ||
| 98 | {0x00580002, nullptr, "GetProgramID"}, | ||
| 99 | {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, | ||
| 100 | {0x01020000, CheckNew3DS, "CheckNew3DS"}, | ||
| 101 | {0x01040000, nullptr, "IsStandardMemoryLayout"}, | ||
| 102 | {0x01050100, nullptr, "IsTitleAllowed"}, | ||
| 103 | }; | ||
| 104 | |||
| 105 | APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) { | ||
| 106 | Register(FunctionTable); | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace APT | ||
| 110 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt_a.h b/src/core/hle/service/apt/apt_a.h deleted file mode 100644 index 331fb5586..000000000 --- a/src/core/hle/service/apt/apt_a.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace APT { | ||
| 11 | |||
| 12 | class APT_A_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | APT_A_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "APT:A"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace APT | ||
| 22 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp deleted file mode 100644 index bb78ee7d7..000000000 --- a/src/core/hle/service/apt/apt_s.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/apt/apt.h" | ||
| 6 | #include "core/hle/service/apt/apt_s.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace APT { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetLockHandle, "GetLockHandle"}, | ||
| 13 | {0x00020080, Initialize, "Initialize"}, | ||
| 14 | {0x00030040, Enable, "Enable"}, | ||
| 15 | {0x00040040, nullptr, "Finalize"}, | ||
| 16 | {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, | ||
| 17 | {0x00060040, GetAppletInfo, "GetAppletInfo"}, | ||
| 18 | {0x00070000, nullptr, "GetLastSignaledAppletId"}, | ||
| 19 | {0x00080000, nullptr, "CountRegisteredApplet"}, | ||
| 20 | {0x00090040, IsRegistered, "IsRegistered"}, | ||
| 21 | {0x000A0040, nullptr, "GetAttribute"}, | ||
| 22 | {0x000B0040, InquireNotification, "InquireNotification"}, | ||
| 23 | {0x000C0104, SendParameter, "SendParameter"}, | ||
| 24 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, | ||
| 25 | {0x000E0080, GlanceParameter, "GlanceParameter"}, | ||
| 26 | {0x000F0100, nullptr, "CancelParameter"}, | ||
| 27 | {0x001000C2, nullptr, "DebugFunc"}, | ||
| 28 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, | ||
| 29 | {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, | ||
| 30 | {0x00130000, nullptr, "GetPreparationState"}, | ||
| 31 | {0x00140040, nullptr, "SetPreparationState"}, | ||
| 32 | {0x00150140, PrepareToStartApplication, "PrepareToStartApplication"}, | ||
| 33 | {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, | ||
| 34 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, | ||
| 35 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, | ||
| 36 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, | ||
| 37 | {0x001A0000, PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, | ||
| 38 | {0x001B00C4, nullptr, "StartApplication"}, | ||
| 39 | {0x001C0000, nullptr, "WakeupApplication"}, | ||
| 40 | {0x001D0000, nullptr, "CancelApplication"}, | ||
| 41 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, | ||
| 42 | {0x001F0084, nullptr, "StartSystemApplet"}, | ||
| 43 | {0x00200044, nullptr, "StartNewestHomeMenu"}, | ||
| 44 | {0x00210000, nullptr, "OrderToCloseApplication"}, | ||
| 45 | {0x00220040, nullptr, "PrepareToCloseApplication"}, | ||
| 46 | {0x00230040, nullptr, "PrepareToJumpToApplication"}, | ||
| 47 | {0x00240044, nullptr, "JumpToApplication"}, | ||
| 48 | {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, | ||
| 49 | {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, | ||
| 50 | {0x00270044, nullptr, "CloseApplication"}, | ||
| 51 | {0x00280044, nullptr, "CloseLibraryApplet"}, | ||
| 52 | {0x00290044, nullptr, "CloseSystemApplet"}, | ||
| 53 | {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, | ||
| 54 | {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, | ||
| 55 | {0x002C0044, nullptr, "JumpToHomeMenu"}, | ||
| 56 | {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, | ||
| 57 | {0x002E0044, nullptr, "LeaveHomeMenu"}, | ||
| 58 | {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, | ||
| 59 | {0x00300044, nullptr, "LeaveResidentApplet"}, | ||
| 60 | {0x00310100, nullptr, "PrepareToDoApplicationJump"}, | ||
| 61 | {0x00320084, nullptr, "DoApplicationJump"}, | ||
| 62 | {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, | ||
| 63 | {0x00340084, nullptr, "SendDeliverArg"}, | ||
| 64 | {0x00350080, nullptr, "ReceiveDeliverArg"}, | ||
| 65 | {0x00360040, nullptr, "LoadSysMenuArg"}, | ||
| 66 | {0x00370042, nullptr, "StoreSysMenuArg"}, | ||
| 67 | {0x00380040, nullptr, "PreloadResidentApplet"}, | ||
| 68 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, | ||
| 69 | {0x003A0044, nullptr, "StartResidentApplet"}, | ||
| 70 | {0x003B0040, nullptr, "CancelLibraryApplet"}, | ||
| 71 | {0x003C0042, nullptr, "SendDspSleep"}, | ||
| 72 | {0x003D0042, nullptr, "SendDspWakeUp"}, | ||
| 73 | {0x003E0080, nullptr, "ReplySleepQuery"}, | ||
| 74 | {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, | ||
| 75 | {0x00400042, nullptr, "SendCaptureBufferInfo"}, | ||
| 76 | {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, | ||
| 77 | {0x00420080, nullptr, "SleepSystem"}, | ||
| 78 | {0x00430040, NotifyToWait, "NotifyToWait"}, | ||
| 79 | {0x00440000, GetSharedFont, "GetSharedFont"}, | ||
| 80 | {0x00450040, nullptr, "GetWirelessRebootInfo"}, | ||
| 81 | {0x00460104, Wrap, "Wrap"}, | ||
| 82 | {0x00470104, Unwrap, "Unwrap"}, | ||
| 83 | {0x00480100, nullptr, "GetProgramInfo"}, | ||
| 84 | {0x00490180, nullptr, "Reboot"}, | ||
| 85 | {0x004A0040, nullptr, "GetCaptureInfo"}, | ||
| 86 | {0x004B00C2, AppletUtility, "AppletUtility"}, | ||
| 87 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, | ||
| 88 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, | ||
| 89 | {0x004E0000, nullptr, "HardwareResetAsync"}, | ||
| 90 | {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||
| 91 | {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||
| 92 | {0x00510080, GetStartupArgument, "GetStartupArgument"}, | ||
| 93 | {0x00520104, nullptr, "Wrap1"}, | ||
| 94 | {0x00530104, nullptr, "Unwrap1"}, | ||
| 95 | {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||
| 96 | {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||
| 97 | {0x00570044, nullptr, "WakeupApplication2"}, | ||
| 98 | {0x00580002, nullptr, "GetProgramID"}, | ||
| 99 | {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, | ||
| 100 | {0x01020000, CheckNew3DS, "CheckNew3DS"}, | ||
| 101 | {0x01040000, nullptr, "IsStandardMemoryLayout"}, | ||
| 102 | {0x01050100, nullptr, "IsTitleAllowed"}, | ||
| 103 | }; | ||
| 104 | |||
| 105 | APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) { | ||
| 106 | Register(FunctionTable); | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace APT | ||
| 110 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt_s.h b/src/core/hle/service/apt/apt_s.h deleted file mode 100644 index 8e87b69af..000000000 --- a/src/core/hle/service/apt/apt_s.h +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace APT { | ||
| 11 | |||
| 12 | // Application and title launching service. These services handle signaling for home/power button as | ||
| 13 | // well. Only one session for either APT service can be open at a time, normally processes close the | ||
| 14 | // service handle immediately once finished using the service. The commands for APT:U and APT:S are | ||
| 15 | // exactly the same, however certain commands are only accessible with APT:S(NS module will call | ||
| 16 | // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. | ||
| 17 | |||
| 18 | /// Interface to "APT:S" service | ||
| 19 | class APT_S_Interface : public Service::Interface { | ||
| 20 | public: | ||
| 21 | APT_S_Interface(); | ||
| 22 | |||
| 23 | std::string GetPortName() const override { | ||
| 24 | return "APT:S"; | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace APT | ||
| 29 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp deleted file mode 100644 index 9dd002590..000000000 --- a/src/core/hle/service/apt/apt_u.cpp +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/apt/apt.h" | ||
| 6 | #include "core/hle/service/apt/apt_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace APT { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, GetLockHandle, "GetLockHandle"}, | ||
| 13 | {0x00020080, Initialize, "Initialize"}, | ||
| 14 | {0x00030040, Enable, "Enable"}, | ||
| 15 | {0x00040040, nullptr, "Finalize"}, | ||
| 16 | {0x00050040, GetAppletManInfo, "GetAppletManInfo"}, | ||
| 17 | {0x00060040, GetAppletInfo, "GetAppletInfo"}, | ||
| 18 | {0x00070000, nullptr, "GetLastSignaledAppletId"}, | ||
| 19 | {0x00080000, nullptr, "CountRegisteredApplet"}, | ||
| 20 | {0x00090040, IsRegistered, "IsRegistered"}, | ||
| 21 | {0x000A0040, nullptr, "GetAttribute"}, | ||
| 22 | {0x000B0040, InquireNotification, "InquireNotification"}, | ||
| 23 | {0x000C0104, SendParameter, "SendParameter"}, | ||
| 24 | {0x000D0080, ReceiveParameter, "ReceiveParameter"}, | ||
| 25 | {0x000E0080, GlanceParameter, "GlanceParameter"}, | ||
| 26 | {0x000F0100, CancelParameter, "CancelParameter"}, | ||
| 27 | {0x001000C2, nullptr, "DebugFunc"}, | ||
| 28 | {0x001100C0, nullptr, "MapProgramIdForDebug"}, | ||
| 29 | {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, | ||
| 30 | {0x00130000, nullptr, "GetPreparationState"}, | ||
| 31 | {0x00140040, nullptr, "SetPreparationState"}, | ||
| 32 | {0x00150140, PrepareToStartApplication, "PrepareToStartApplication"}, | ||
| 33 | {0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"}, | ||
| 34 | {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, | ||
| 35 | {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, | ||
| 36 | {0x00190040, nullptr, "PrepareToStartSystemApplet"}, | ||
| 37 | {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, | ||
| 38 | {0x001B00C4, nullptr, "StartApplication"}, | ||
| 39 | {0x001C0000, nullptr, "WakeupApplication"}, | ||
| 40 | {0x001D0000, nullptr, "CancelApplication"}, | ||
| 41 | {0x001E0084, StartLibraryApplet, "StartLibraryApplet"}, | ||
| 42 | {0x001F0084, nullptr, "StartSystemApplet"}, | ||
| 43 | {0x00200044, nullptr, "StartNewestHomeMenu"}, | ||
| 44 | {0x00210000, nullptr, "OrderToCloseApplication"}, | ||
| 45 | {0x00220040, nullptr, "PrepareToCloseApplication"}, | ||
| 46 | {0x00230040, nullptr, "PrepareToJumpToApplication"}, | ||
| 47 | {0x00240044, nullptr, "JumpToApplication"}, | ||
| 48 | {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, | ||
| 49 | {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, | ||
| 50 | {0x00270044, nullptr, "CloseApplication"}, | ||
| 51 | {0x00280044, nullptr, "CloseLibraryApplet"}, | ||
| 52 | {0x00290044, nullptr, "CloseSystemApplet"}, | ||
| 53 | {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, | ||
| 54 | {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, | ||
| 55 | {0x002C0044, nullptr, "JumpToHomeMenu"}, | ||
| 56 | {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"}, | ||
| 57 | {0x002E0044, nullptr, "LeaveHomeMenu"}, | ||
| 58 | {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, | ||
| 59 | {0x00300044, nullptr, "LeaveResidentApplet"}, | ||
| 60 | {0x00310100, nullptr, "PrepareToDoApplicationJump"}, | ||
| 61 | {0x00320084, nullptr, "DoApplicationJump"}, | ||
| 62 | {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, | ||
| 63 | {0x00340084, nullptr, "SendDeliverArg"}, | ||
| 64 | {0x00350080, nullptr, "ReceiveDeliverArg"}, | ||
| 65 | {0x00360040, nullptr, "LoadSysMenuArg"}, | ||
| 66 | {0x00370042, nullptr, "StoreSysMenuArg"}, | ||
| 67 | {0x00380040, nullptr, "PreloadResidentApplet"}, | ||
| 68 | {0x00390040, nullptr, "PrepareToStartResidentApplet"}, | ||
| 69 | {0x003A0044, nullptr, "StartResidentApplet"}, | ||
| 70 | {0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"}, | ||
| 71 | {0x003C0042, nullptr, "SendDspSleep"}, | ||
| 72 | {0x003D0042, nullptr, "SendDspWakeUp"}, | ||
| 73 | {0x003E0080, nullptr, "ReplySleepQuery"}, | ||
| 74 | {0x003F0040, nullptr, "ReplySleepNotificationComplete"}, | ||
| 75 | {0x00400042, nullptr, "SendCaptureBufferInfo"}, | ||
| 76 | {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, | ||
| 77 | {0x00420080, nullptr, "SleepSystem"}, | ||
| 78 | {0x00430040, NotifyToWait, "NotifyToWait"}, | ||
| 79 | {0x00440000, GetSharedFont, "GetSharedFont"}, | ||
| 80 | {0x00450040, nullptr, "GetWirelessRebootInfo"}, | ||
| 81 | {0x00460104, Wrap, "Wrap"}, | ||
| 82 | {0x00470104, Unwrap, "Unwrap"}, | ||
| 83 | {0x00480100, nullptr, "GetProgramInfo"}, | ||
| 84 | {0x00490180, nullptr, "Reboot"}, | ||
| 85 | {0x004A0040, nullptr, "GetCaptureInfo"}, | ||
| 86 | {0x004B00C2, AppletUtility, "AppletUtility"}, | ||
| 87 | {0x004C0000, nullptr, "SetFatalErrDispMode"}, | ||
| 88 | {0x004D0080, nullptr, "GetAppletProgramInfo"}, | ||
| 89 | {0x004E0000, nullptr, "HardwareResetAsync"}, | ||
| 90 | {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | ||
| 91 | {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | ||
| 92 | {0x00510080, GetStartupArgument, "GetStartupArgument"}, | ||
| 93 | {0x00520104, nullptr, "Wrap1"}, | ||
| 94 | {0x00530104, nullptr, "Unwrap1"}, | ||
| 95 | {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, | ||
| 96 | {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, | ||
| 97 | {0x00580002, nullptr, "GetProgramID"}, | ||
| 98 | {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, | ||
| 99 | {0x01020000, CheckNew3DS, "CheckNew3DS"}, | ||
| 100 | }; | ||
| 101 | |||
| 102 | APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) { | ||
| 103 | Register(FunctionTable); | ||
| 104 | } | ||
| 105 | |||
| 106 | } // namespace APT | ||
| 107 | } // namespace Service | ||
diff --git a/src/core/hle/service/apt/apt_u.h b/src/core/hle/service/apt/apt_u.h deleted file mode 100644 index 8c7fe0ccb..000000000 --- a/src/core/hle/service/apt/apt_u.h +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace APT { | ||
| 11 | |||
| 12 | // Application and title launching service. These services handle signaling for home/power button as | ||
| 13 | // well. Only one session for either APT service can be open at a time, normally processes close the | ||
| 14 | // service handle immediately once finished using the service. The commands for APT:U and APT:S are | ||
| 15 | // exactly the same, however certain commands are only accessible with APT:S(NS module will call | ||
| 16 | // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. | ||
| 17 | |||
| 18 | /// Interface to "APT:U" service | ||
| 19 | class APT_U_Interface : public Service::Interface { | ||
| 20 | public: | ||
| 21 | APT_U_Interface(); | ||
| 22 | |||
| 23 | std::string GetPortName() const override { | ||
| 24 | return "APT:U"; | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace APT | ||
| 29 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp deleted file mode 100644 index 6d2474702..000000000 --- a/src/core/hle/service/apt/bcfnt/bcfnt.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/apt/bcfnt/bcfnt.h" | ||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace APT { | ||
| 10 | namespace BCFNT { | ||
| 11 | |||
| 12 | void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr new_address) { | ||
| 13 | static const u32 SharedFontStartOffset = 0x80; | ||
| 14 | const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset); | ||
| 15 | |||
| 16 | CFNT cfnt; | ||
| 17 | memcpy(&cfnt, cfnt_ptr, sizeof(cfnt)); | ||
| 18 | |||
| 19 | u32 assumed_cmap_offset = 0; | ||
| 20 | u32 assumed_cwdh_offset = 0; | ||
| 21 | u32 assumed_tglp_offset = 0; | ||
| 22 | u32 first_cmap_offset = 0; | ||
| 23 | u32 first_cwdh_offset = 0; | ||
| 24 | u32 first_tglp_offset = 0; | ||
| 25 | |||
| 26 | // First discover the location of sections so that the rebase offset can be auto-detected | ||
| 27 | u32 current_offset = SharedFontStartOffset + cfnt.header_size; | ||
| 28 | for (unsigned block = 0; block < cfnt.num_blocks; ++block) { | ||
| 29 | const u8* data = shared_font->GetPointer(current_offset); | ||
| 30 | |||
| 31 | SectionHeader section_header; | ||
| 32 | memcpy(§ion_header, data, sizeof(section_header)); | ||
| 33 | |||
| 34 | if (first_cmap_offset == 0 && memcmp(section_header.magic, "CMAP", 4) == 0) { | ||
| 35 | first_cmap_offset = current_offset; | ||
| 36 | } else if (first_cwdh_offset == 0 && memcmp(section_header.magic, "CWDH", 4) == 0) { | ||
| 37 | first_cwdh_offset = current_offset; | ||
| 38 | } else if (first_tglp_offset == 0 && memcmp(section_header.magic, "TGLP", 4) == 0) { | ||
| 39 | first_tglp_offset = current_offset; | ||
| 40 | } else if (memcmp(section_header.magic, "FINF", 4) == 0) { | ||
| 41 | BCFNT::FINF finf; | ||
| 42 | memcpy(&finf, data, sizeof(finf)); | ||
| 43 | |||
| 44 | assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader); | ||
| 45 | assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader); | ||
| 46 | assumed_tglp_offset = finf.tglp_offset - sizeof(SectionHeader); | ||
| 47 | } | ||
| 48 | |||
| 49 | current_offset += section_header.section_size; | ||
| 50 | } | ||
| 51 | |||
| 52 | u32 previous_base = assumed_cmap_offset - first_cmap_offset; | ||
| 53 | ASSERT(previous_base == assumed_cwdh_offset - first_cwdh_offset); | ||
| 54 | ASSERT(previous_base == assumed_tglp_offset - first_tglp_offset); | ||
| 55 | |||
| 56 | u32 offset = new_address - previous_base; | ||
| 57 | |||
| 58 | // Reset pointer back to start of sections and do the actual rebase | ||
| 59 | current_offset = SharedFontStartOffset + cfnt.header_size; | ||
| 60 | for (unsigned block = 0; block < cfnt.num_blocks; ++block) { | ||
| 61 | u8* data = shared_font->GetPointer(current_offset); | ||
| 62 | |||
| 63 | SectionHeader section_header; | ||
| 64 | memcpy(§ion_header, data, sizeof(section_header)); | ||
| 65 | |||
| 66 | if (memcmp(section_header.magic, "FINF", 4) == 0) { | ||
| 67 | BCFNT::FINF finf; | ||
| 68 | memcpy(&finf, data, sizeof(finf)); | ||
| 69 | |||
| 70 | // Relocate the offsets in the FINF section | ||
| 71 | finf.cmap_offset += offset; | ||
| 72 | finf.cwdh_offset += offset; | ||
| 73 | finf.tglp_offset += offset; | ||
| 74 | |||
| 75 | memcpy(data, &finf, sizeof(finf)); | ||
| 76 | } else if (memcmp(section_header.magic, "CMAP", 4) == 0) { | ||
| 77 | BCFNT::CMAP cmap; | ||
| 78 | memcpy(&cmap, data, sizeof(cmap)); | ||
| 79 | |||
| 80 | // Relocate the offsets in the CMAP section | ||
| 81 | if (cmap.next_cmap_offset != 0) | ||
| 82 | cmap.next_cmap_offset += offset; | ||
| 83 | |||
| 84 | memcpy(data, &cmap, sizeof(cmap)); | ||
| 85 | } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { | ||
| 86 | BCFNT::CWDH cwdh; | ||
| 87 | memcpy(&cwdh, data, sizeof(cwdh)); | ||
| 88 | |||
| 89 | // Relocate the offsets in the CWDH section | ||
| 90 | if (cwdh.next_cwdh_offset != 0) | ||
| 91 | cwdh.next_cwdh_offset += offset; | ||
| 92 | |||
| 93 | memcpy(data, &cwdh, sizeof(cwdh)); | ||
| 94 | } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { | ||
| 95 | BCFNT::TGLP tglp; | ||
| 96 | memcpy(&tglp, data, sizeof(tglp)); | ||
| 97 | |||
| 98 | // Relocate the offsets in the TGLP section | ||
| 99 | tglp.sheet_data_offset += offset; | ||
| 100 | |||
| 101 | memcpy(data, &tglp, sizeof(tglp)); | ||
| 102 | } | ||
| 103 | |||
| 104 | current_offset += section_header.section_size; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | } // namespace BCFNT | ||
| 109 | } // namespace APT | ||
| 110 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.h b/src/core/hle/service/apt/bcfnt/bcfnt.h deleted file mode 100644 index 453bf7606..000000000 --- a/src/core/hle/service/apt/bcfnt/bcfnt.h +++ /dev/null | |||
| @@ -1,92 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace APT { | ||
| 13 | namespace BCFNT { ///< BCFNT Shared Font file structures | ||
| 14 | |||
| 15 | struct CFNT { | ||
| 16 | u8 magic[4]; | ||
| 17 | u16_le endianness; | ||
| 18 | u16_le header_size; | ||
| 19 | u32_le version; | ||
| 20 | u32_le file_size; | ||
| 21 | u32_le num_blocks; | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct SectionHeader { | ||
| 25 | u8 magic[4]; | ||
| 26 | u32_le section_size; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct FINF { | ||
| 30 | u8 magic[4]; | ||
| 31 | u32_le section_size; | ||
| 32 | u8 font_type; | ||
| 33 | u8 line_feed; | ||
| 34 | u16_le alter_char_index; | ||
| 35 | u8 default_width[3]; | ||
| 36 | u8 encoding; | ||
| 37 | u32_le tglp_offset; | ||
| 38 | u32_le cwdh_offset; | ||
| 39 | u32_le cmap_offset; | ||
| 40 | u8 height; | ||
| 41 | u8 width; | ||
| 42 | u8 ascent; | ||
| 43 | u8 reserved; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct TGLP { | ||
| 47 | u8 magic[4]; | ||
| 48 | u32_le section_size; | ||
| 49 | u8 cell_width; | ||
| 50 | u8 cell_height; | ||
| 51 | u8 baseline_position; | ||
| 52 | u8 max_character_width; | ||
| 53 | u32_le sheet_size; | ||
| 54 | u16_le num_sheets; | ||
| 55 | u16_le sheet_image_format; | ||
| 56 | u16_le num_columns; | ||
| 57 | u16_le num_rows; | ||
| 58 | u16_le sheet_width; | ||
| 59 | u16_le sheet_height; | ||
| 60 | u32_le sheet_data_offset; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct CMAP { | ||
| 64 | u8 magic[4]; | ||
| 65 | u32_le section_size; | ||
| 66 | u16_le code_begin; | ||
| 67 | u16_le code_end; | ||
| 68 | u16_le mapping_method; | ||
| 69 | u16_le reserved; | ||
| 70 | u32_le next_cmap_offset; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct CWDH { | ||
| 74 | u8 magic[4]; | ||
| 75 | u32_le section_size; | ||
| 76 | u16_le start_index; | ||
| 77 | u16_le end_index; | ||
| 78 | u32_le next_cwdh_offset; | ||
| 79 | }; | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Relocates the internal addresses of the BCFNT Shared Font to the new base. The current base will | ||
| 83 | * be auto-detected based on the file headers. | ||
| 84 | * | ||
| 85 | * @param shared_font SharedMemory object that contains the Shared Font | ||
| 86 | * @param new_address New base for the offsets in the structure. | ||
| 87 | */ | ||
| 88 | void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr new_address); | ||
| 89 | |||
| 90 | } // namespace BCFNT | ||
| 91 | } // namespace APT | ||
| 92 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp deleted file mode 100644 index 2bba3aff6..000000000 --- a/src/core/hle/service/boss/boss.cpp +++ /dev/null | |||
| @@ -1,994 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cinttypes> | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/hle/ipc.h" | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/boss/boss.h" | ||
| 10 | #include "core/hle/service/boss/boss_p.h" | ||
| 11 | #include "core/hle/service/boss/boss_u.h" | ||
| 12 | #include "core/hle/service/service.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace BOSS { | ||
| 16 | |||
| 17 | static u32 new_arrival_flag; | ||
| 18 | static u32 ns_data_new_flag; | ||
| 19 | static u32 output_flag; | ||
| 20 | |||
| 21 | void InitializeSession(Service::Interface* self) { | ||
| 22 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 23 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 24 | u64 unk_param = ((u64)cmd_buff[1] | ((u64)cmd_buff[2] << 32)); | ||
| 25 | u32 translation = cmd_buff[3]; | ||
| 26 | u32 unk_param4 = cmd_buff[4]; | ||
| 27 | |||
| 28 | if (translation != IPC::CallingPidDesc()) { | ||
| 29 | cmd_buff[0] = IPC::MakeHeader(0, 0x1, 0); // 0x40 | ||
| 30 | cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; | ||
| 31 | LOG_ERROR(Service_BOSS, "The translation was invalid, translation=0x%08X", translation); | ||
| 32 | return; | ||
| 33 | } | ||
| 34 | |||
| 35 | cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); | ||
| 36 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 37 | |||
| 38 | LOG_WARNING(Service_BOSS, | ||
| 39 | "(STUBBED) unk_param=0x%016" PRIX64 ", translation=0x%08X, unk_param4=0x%08X", | ||
| 40 | unk_param, translation, unk_param4); | ||
| 41 | } | ||
| 42 | |||
| 43 | void RegisterStorage(Service::Interface* self) { | ||
| 44 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 45 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 46 | u32 unk_param1 = cmd_buff[1]; | ||
| 47 | u32 unk_param2 = cmd_buff[2]; | ||
| 48 | u32 unk_param3 = cmd_buff[3]; | ||
| 49 | u32 unk_flag = cmd_buff[4] & 0xFF; | ||
| 50 | |||
| 51 | cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0); | ||
| 52 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 53 | |||
| 54 | LOG_WARNING( | ||
| 55 | Service_BOSS, | ||
| 56 | "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, unk_flag=0x%08X", | ||
| 57 | unk_param1, unk_param2, unk_param3, unk_flag); | ||
| 58 | } | ||
| 59 | |||
| 60 | void UnregisterStorage(Service::Interface* self) { | ||
| 61 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 62 | |||
| 63 | cmd_buff[0] = IPC::MakeHeader(0x3, 0x1, 0); | ||
| 64 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 65 | |||
| 66 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 67 | } | ||
| 68 | |||
| 69 | void GetStorageInfo(Service::Interface* self) { | ||
| 70 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 71 | |||
| 72 | cmd_buff[0] = IPC::MakeHeader(0x4, 0x2, 0); | ||
| 73 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 74 | cmd_buff[2] = 0; // stub 0 | ||
| 75 | |||
| 76 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 77 | } | ||
| 78 | |||
| 79 | void RegisterPrivateRootCa(Service::Interface* self) { | ||
| 80 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 81 | |||
| 82 | u32 translation = cmd_buff[2]; | ||
| 83 | u32 buff_addr = cmd_buff[3]; | ||
| 84 | u32 buff_size = (translation >> 4); | ||
| 85 | |||
| 86 | cmd_buff[0] = IPC::MakeHeader(0x5, 0x1, 0x2); | ||
| 87 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 88 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 89 | cmd_buff[3] = buff_addr; | ||
| 90 | |||
| 91 | LOG_WARNING(Service_BOSS, "(STUBBED) translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 92 | translation, buff_addr, buff_size); | ||
| 93 | } | ||
| 94 | |||
| 95 | void RegisterPrivateClientCert(Service::Interface* self) { | ||
| 96 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 97 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 98 | u32 unk_param1 = cmd_buff[1]; | ||
| 99 | u32 unk_param2 = cmd_buff[2]; | ||
| 100 | u32 translation1 = cmd_buff[3]; | ||
| 101 | u32 buff1_addr = cmd_buff[4]; | ||
| 102 | u32 buff1_size = (translation1 >> 4); | ||
| 103 | u32 translation2 = cmd_buff[5]; | ||
| 104 | u32 buff2_addr = cmd_buff[6]; | ||
| 105 | u32 buff2_size = (translation2 >> 4); | ||
| 106 | |||
| 107 | cmd_buff[0] = IPC::MakeHeader(0x6, 0x1, 0x4); | ||
| 108 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 109 | cmd_buff[2] = (buff1_size << 4 | 0xA); | ||
| 110 | cmd_buff[3] = buff1_addr; | ||
| 111 | cmd_buff[2] = (buff2_size << 4 | 0xA); | ||
| 112 | cmd_buff[3] = buff2_addr; | ||
| 113 | |||
| 114 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, " | ||
| 115 | "translation1=0x%08X, buff1_addr=0x%08X, buff1_size=0x%08X, " | ||
| 116 | "translation2=0x%08X, buff2_addr=0x%08X, buff2_size=0x%08X", | ||
| 117 | unk_param1, unk_param2, translation1, buff1_addr, buff1_size, translation2, | ||
| 118 | buff2_addr, buff2_size); | ||
| 119 | } | ||
| 120 | |||
| 121 | void GetNewArrivalFlag(Service::Interface* self) { | ||
| 122 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 123 | |||
| 124 | cmd_buff[0] = IPC::MakeHeader(0x7, 0x2, 0); | ||
| 125 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 126 | cmd_buff[2] = new_arrival_flag; | ||
| 127 | |||
| 128 | LOG_WARNING(Service_BOSS, "(STUBBED) new_arrival_flag=%u", new_arrival_flag); | ||
| 129 | } | ||
| 130 | |||
| 131 | void RegisterNewArrivalEvent(Service::Interface* self) { | ||
| 132 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 133 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 134 | u32 unk_param1 = cmd_buff[1]; | ||
| 135 | u32 unk_param2 = cmd_buff[2]; | ||
| 136 | |||
| 137 | cmd_buff[0] = IPC::MakeHeader(0x8, 0x1, 0); | ||
| 138 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 139 | |||
| 140 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X", unk_param1, | ||
| 141 | unk_param2); | ||
| 142 | } | ||
| 143 | |||
| 144 | void SetOptoutFlag(Service::Interface* self) { | ||
| 145 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 146 | |||
| 147 | output_flag = cmd_buff[1] & 0xFF; | ||
| 148 | |||
| 149 | cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); | ||
| 150 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 151 | |||
| 152 | LOG_WARNING(Service_BOSS, "output_flag=%u", output_flag); | ||
| 153 | } | ||
| 154 | |||
| 155 | void GetOptoutFlag(Service::Interface* self) { | ||
| 156 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 157 | |||
| 158 | cmd_buff[0] = IPC::MakeHeader(0xA, 0x2, 0); | ||
| 159 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 160 | cmd_buff[2] = output_flag; | ||
| 161 | |||
| 162 | LOG_WARNING(Service_BOSS, "output_flag=%u", output_flag); | ||
| 163 | } | ||
| 164 | |||
| 165 | void RegisterTask(Service::Interface* self) { | ||
| 166 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 167 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 168 | u32 unk_param1 = cmd_buff[1]; | ||
| 169 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 170 | u32 unk_param3 = cmd_buff[3] & 0xFF; | ||
| 171 | u32 translation = cmd_buff[4]; | ||
| 172 | u32 buff_addr = cmd_buff[5]; | ||
| 173 | u32 buff_size = (translation >> 4); | ||
| 174 | |||
| 175 | cmd_buff[0] = IPC::MakeHeader(0xB, 0x1, 0x2); | ||
| 176 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 177 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 178 | cmd_buff[3] = buff_addr; | ||
| 179 | |||
| 180 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 181 | "translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 182 | unk_param1, unk_param2, unk_param3, translation, buff_addr, buff_size); | ||
| 183 | } | ||
| 184 | |||
| 185 | void UnregisterTask(Service::Interface* self) { | ||
| 186 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 187 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 188 | u32 unk_param1 = cmd_buff[1]; | ||
| 189 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 190 | u32 translation = cmd_buff[3]; | ||
| 191 | u32 buff_addr = cmd_buff[4]; | ||
| 192 | u32 buff_size = (translation >> 4); | ||
| 193 | |||
| 194 | cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0x2); | ||
| 195 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 196 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 197 | cmd_buff[3] = buff_addr; | ||
| 198 | |||
| 199 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, translation=0x%08X, " | ||
| 200 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 201 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 202 | } | ||
| 203 | |||
| 204 | void ReconfigureTask(Service::Interface* self) { | ||
| 205 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 206 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 207 | u32 unk_param1 = cmd_buff[1]; | ||
| 208 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 209 | u32 translation = cmd_buff[3]; | ||
| 210 | u32 buff_addr = cmd_buff[4]; | ||
| 211 | u32 buff_size = (translation >> 4); | ||
| 212 | |||
| 213 | cmd_buff[0] = IPC::MakeHeader(0xD, 0x1, 0x2); | ||
| 214 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 215 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 216 | cmd_buff[3] = buff_addr; | ||
| 217 | |||
| 218 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, translation=0x%08X, " | ||
| 219 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 220 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 221 | } | ||
| 222 | |||
| 223 | void GetTaskIdList(Service::Interface* self) { | ||
| 224 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 225 | |||
| 226 | cmd_buff[0] = IPC::MakeHeader(0xE, 0x1, 0); | ||
| 227 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 228 | |||
| 229 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 230 | } | ||
| 231 | |||
| 232 | void GetStepIdList(Service::Interface* self) { | ||
| 233 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 234 | |||
| 235 | u32 translation = cmd_buff[2]; | ||
| 236 | u32 buff_addr = cmd_buff[3]; | ||
| 237 | u32 buff_size = (translation >> 4); | ||
| 238 | |||
| 239 | cmd_buff[0] = IPC::MakeHeader(0xF, 0x1, 0x2); | ||
| 240 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 241 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 242 | cmd_buff[3] = buff_addr; | ||
| 243 | |||
| 244 | LOG_WARNING(Service_BOSS, "(STUBBED) translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 245 | translation, buff_addr, buff_size); | ||
| 246 | } | ||
| 247 | |||
| 248 | void GetNsDataIdList(Service::Interface* self) { | ||
| 249 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 250 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 251 | u32 unk_param1 = cmd_buff[1]; | ||
| 252 | u32 unk_param2 = cmd_buff[2]; | ||
| 253 | u32 unk_param3 = cmd_buff[3]; | ||
| 254 | u32 unk_param4 = cmd_buff[4]; | ||
| 255 | u32 translation = cmd_buff[5]; | ||
| 256 | u32 buff_addr = cmd_buff[6]; | ||
| 257 | u32 buff_size = (translation >> 4); | ||
| 258 | |||
| 259 | cmd_buff[0] = IPC::MakeHeader(0x10, 0x3, 0x2); | ||
| 260 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 261 | cmd_buff[2] = 0; // stub 0 (16 bit value) | ||
| 262 | cmd_buff[3] = 0; // stub 0 (16 bit value) | ||
| 263 | cmd_buff[4] = (buff_size << 4 | 0xC); | ||
| 264 | cmd_buff[5] = buff_addr; | ||
| 265 | |||
| 266 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 267 | "unk_param4=0x%08X, translation=0x%08X, " | ||
| 268 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 269 | unk_param1, unk_param2, unk_param3, unk_param4, translation, buff_addr, buff_size); | ||
| 270 | } | ||
| 271 | |||
| 272 | void GetOwnNsDataIdList(Service::Interface* self) { | ||
| 273 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 274 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 275 | u32 unk_param1 = cmd_buff[1]; | ||
| 276 | u32 unk_param2 = cmd_buff[2]; | ||
| 277 | u32 unk_param3 = cmd_buff[3]; | ||
| 278 | u32 unk_param4 = cmd_buff[4]; | ||
| 279 | u32 translation = cmd_buff[5]; | ||
| 280 | u32 buff_addr = cmd_buff[6]; | ||
| 281 | u32 buff_size = (translation >> 4); | ||
| 282 | |||
| 283 | cmd_buff[0] = IPC::MakeHeader(0x11, 0x3, 0x2); | ||
| 284 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 285 | cmd_buff[2] = 0; // stub 0 (16 bit value) | ||
| 286 | cmd_buff[3] = 0; // stub 0 (16 bit value) | ||
| 287 | cmd_buff[4] = (buff_size << 4 | 0xC); | ||
| 288 | cmd_buff[5] = buff_addr; | ||
| 289 | |||
| 290 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 291 | "unk_param4=0x%08X, translation=0x%08X, " | ||
| 292 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 293 | unk_param1, unk_param2, unk_param3, unk_param4, translation, buff_addr, buff_size); | ||
| 294 | } | ||
| 295 | |||
| 296 | void GetNewDataNsDataIdList(Service::Interface* self) { | ||
| 297 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 298 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 299 | u32 unk_param1 = cmd_buff[1]; | ||
| 300 | u32 unk_param2 = cmd_buff[2]; | ||
| 301 | u32 unk_param3 = cmd_buff[3]; | ||
| 302 | u32 unk_param4 = cmd_buff[4]; | ||
| 303 | u32 translation = cmd_buff[5]; | ||
| 304 | u32 buff_addr = cmd_buff[6]; | ||
| 305 | u32 buff_size = (translation >> 4); | ||
| 306 | |||
| 307 | cmd_buff[0] = IPC::MakeHeader(0x12, 0x3, 0x2); | ||
| 308 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 309 | cmd_buff[2] = 0; // stub 0 (16 bit value) | ||
| 310 | cmd_buff[3] = 0; // stub 0 (16 bit value) | ||
| 311 | cmd_buff[4] = (buff_size << 4 | 0xC); | ||
| 312 | cmd_buff[5] = buff_addr; | ||
| 313 | |||
| 314 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 315 | "unk_param4=0x%08X, translation=0x%08X, " | ||
| 316 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 317 | unk_param1, unk_param2, unk_param3, unk_param4, translation, buff_addr, buff_size); | ||
| 318 | } | ||
| 319 | |||
| 320 | void GetOwnNewDataNsDataIdList(Service::Interface* self) { | ||
| 321 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 322 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 323 | u32 unk_param1 = cmd_buff[1]; | ||
| 324 | u32 unk_param2 = cmd_buff[2]; | ||
| 325 | u32 unk_param3 = cmd_buff[3]; | ||
| 326 | u32 unk_param4 = cmd_buff[4]; | ||
| 327 | u32 translation = cmd_buff[5]; | ||
| 328 | u32 buff_addr = cmd_buff[6]; | ||
| 329 | u32 buff_size = (translation >> 4); | ||
| 330 | |||
| 331 | cmd_buff[0] = IPC::MakeHeader(0x13, 0x3, 0x2); | ||
| 332 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 333 | cmd_buff[2] = 0; // stub 0 (16 bit value) | ||
| 334 | cmd_buff[3] = 0; // stub 0 (16 bit value) | ||
| 335 | cmd_buff[4] = (buff_size << 4 | 0xC); | ||
| 336 | cmd_buff[5] = buff_addr; | ||
| 337 | |||
| 338 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 339 | "unk_param4=0x%08X, translation=0x%08X, " | ||
| 340 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 341 | unk_param1, unk_param2, unk_param3, unk_param4, translation, buff_addr, buff_size); | ||
| 342 | } | ||
| 343 | |||
| 344 | void SendProperty(Service::Interface* self) { | ||
| 345 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 346 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 347 | u32 unk_param1 = cmd_buff[1]; | ||
| 348 | u32 unk_param2 = cmd_buff[2]; | ||
| 349 | u32 translation = cmd_buff[3]; | ||
| 350 | u32 buff_addr = cmd_buff[4]; | ||
| 351 | u32 buff_size = (translation >> 4); | ||
| 352 | |||
| 353 | cmd_buff[0] = IPC::MakeHeader(0x14, 0x1, 0x2); | ||
| 354 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 355 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 356 | cmd_buff[3] = buff_addr; | ||
| 357 | |||
| 358 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, translation=0x%08X, " | ||
| 359 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 360 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 361 | } | ||
| 362 | |||
| 363 | void SendPropertyHandle(Service::Interface* self) { | ||
| 364 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 365 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 366 | u32 unk_param1 = cmd_buff[2] & 0xFF; | ||
| 367 | u32 translation = cmd_buff[3]; | ||
| 368 | u32 buff_addr = cmd_buff[4]; | ||
| 369 | u32 buff_size = (translation >> 4); | ||
| 370 | |||
| 371 | cmd_buff[0] = IPC::MakeHeader(0x15, 0x1, 0x2); | ||
| 372 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 373 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 374 | cmd_buff[3] = buff_addr; | ||
| 375 | |||
| 376 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 377 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 378 | unk_param1, translation, buff_addr, buff_size); | ||
| 379 | } | ||
| 380 | |||
| 381 | void ReceiveProperty(Service::Interface* self) { | ||
| 382 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 383 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 384 | u32 unk_param1 = cmd_buff[1]; | ||
| 385 | u32 buff_size = cmd_buff[2]; | ||
| 386 | u32 translation = cmd_buff[3]; | ||
| 387 | u32 buff_addr = cmd_buff[4]; | ||
| 388 | |||
| 389 | cmd_buff[0] = IPC::MakeHeader(0x16, 0x2, 0x2); | ||
| 390 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 391 | cmd_buff[2] = 0; // stub 0 (32 bit value) | ||
| 392 | cmd_buff[2] = (buff_size << 4 | 0xC); | ||
| 393 | cmd_buff[3] = buff_addr; | ||
| 394 | |||
| 395 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, buff_size=0x%08X, " | ||
| 396 | "translation=0x%08X, buff_addr=0x%08X", | ||
| 397 | unk_param1, buff_size, translation, buff_addr); | ||
| 398 | } | ||
| 399 | |||
| 400 | void UpdateTaskInterval(Service::Interface* self) { | ||
| 401 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 402 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 403 | u32 unk_param1 = cmd_buff[1]; | ||
| 404 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 405 | u32 translation = cmd_buff[3]; | ||
| 406 | u32 buff_addr = cmd_buff[4]; | ||
| 407 | u32 buff_size = (translation >> 4); | ||
| 408 | |||
| 409 | cmd_buff[0] = IPC::MakeHeader(0x17, 0x1, 0x2); | ||
| 410 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 411 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 412 | cmd_buff[3] = buff_addr; | ||
| 413 | |||
| 414 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, " | ||
| 415 | "translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 416 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 417 | } | ||
| 418 | |||
| 419 | void UpdateTaskCount(Service::Interface* self) { | ||
| 420 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 421 | |||
| 422 | u32 buff_size = cmd_buff[1]; | ||
| 423 | u32 unk_param2 = cmd_buff[2]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 424 | u32 translation = cmd_buff[3]; | ||
| 425 | u32 buff_addr = cmd_buff[4]; | ||
| 426 | |||
| 427 | cmd_buff[0] = IPC::MakeHeader(0x18, 0x1, 0x2); | ||
| 428 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 429 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 430 | cmd_buff[3] = buff_addr; | ||
| 431 | |||
| 432 | LOG_WARNING(Service_BOSS, "(STUBBED) buff_size=0x%08X, unk_param2=0x%08X, " | ||
| 433 | "translation=0x%08X, buff_addr=0x%08X", | ||
| 434 | buff_size, unk_param2, translation, buff_addr); | ||
| 435 | } | ||
| 436 | |||
| 437 | void GetTaskInterval(Service::Interface* self) { | ||
| 438 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 439 | |||
| 440 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 441 | u32 translation = cmd_buff[2]; | ||
| 442 | u32 buff_addr = cmd_buff[3]; | ||
| 443 | u32 buff_size = (translation >> 4); | ||
| 444 | |||
| 445 | cmd_buff[0] = IPC::MakeHeader(0x19, 0x2, 0x2); | ||
| 446 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 447 | cmd_buff[2] = 0; // stub 0 ( 32bit value) | ||
| 448 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 449 | cmd_buff[4] = buff_addr; | ||
| 450 | |||
| 451 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 452 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 453 | unk_param1, translation, buff_addr, buff_size); | ||
| 454 | } | ||
| 455 | |||
| 456 | void GetTaskCount(Service::Interface* self) { | ||
| 457 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 458 | |||
| 459 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 460 | u32 translation = cmd_buff[2]; | ||
| 461 | u32 buff_addr = cmd_buff[3]; | ||
| 462 | u32 buff_size = (translation >> 4); | ||
| 463 | |||
| 464 | cmd_buff[0] = IPC::MakeHeader(0x1A, 0x2, 0x2); | ||
| 465 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 466 | cmd_buff[2] = 0; // stub 0 ( 32bit value) | ||
| 467 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 468 | cmd_buff[4] = buff_addr; | ||
| 469 | |||
| 470 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 471 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 472 | unk_param1, translation, buff_addr, buff_size); | ||
| 473 | } | ||
| 474 | |||
| 475 | void GetTaskServiceStatus(Service::Interface* self) { | ||
| 476 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 477 | |||
| 478 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 479 | u32 translation = cmd_buff[2]; | ||
| 480 | u32 buff_addr = cmd_buff[3]; | ||
| 481 | u32 buff_size = (translation >> 4); | ||
| 482 | |||
| 483 | cmd_buff[0] = IPC::MakeHeader(0x1B, 0x2, 0x2); | ||
| 484 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 485 | cmd_buff[2] = 0; // stub 0 ( 8bit value) | ||
| 486 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 487 | cmd_buff[4] = buff_addr; | ||
| 488 | |||
| 489 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 490 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 491 | unk_param1, translation, buff_addr, buff_size); | ||
| 492 | } | ||
| 493 | |||
| 494 | void StartTask(Service::Interface* self) { | ||
| 495 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 496 | |||
| 497 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 498 | u32 translation = cmd_buff[2]; | ||
| 499 | u32 buff_addr = cmd_buff[3]; | ||
| 500 | u32 buff_size = (translation >> 4); | ||
| 501 | |||
| 502 | cmd_buff[0] = IPC::MakeHeader(0x1C, 0x1, 0x2); | ||
| 503 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 504 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 505 | cmd_buff[3] = buff_addr; | ||
| 506 | |||
| 507 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 508 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 509 | unk_param1, translation, buff_addr, buff_size); | ||
| 510 | } | ||
| 511 | |||
| 512 | void StartTaskImmediate(Service::Interface* self) { | ||
| 513 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 514 | |||
| 515 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 516 | u32 translation = cmd_buff[2]; | ||
| 517 | u32 buff_addr = cmd_buff[3]; | ||
| 518 | u32 buff_size = (translation >> 4); | ||
| 519 | |||
| 520 | cmd_buff[0] = IPC::MakeHeader(0x1D, 0x1, 0x2); | ||
| 521 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 522 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 523 | cmd_buff[3] = buff_addr; | ||
| 524 | |||
| 525 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 526 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 527 | unk_param1, translation, buff_addr, buff_size); | ||
| 528 | } | ||
| 529 | |||
| 530 | void CancelTask(Service::Interface* self) { | ||
| 531 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 532 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 533 | u32 unk_param1 = cmd_buff[1]; | ||
| 534 | u32 translation = cmd_buff[2]; | ||
| 535 | u32 buff_addr = cmd_buff[3]; | ||
| 536 | u32 buff_size = (translation >> 4); | ||
| 537 | |||
| 538 | cmd_buff[0] = IPC::MakeHeader(0x1E, 0x1, 0x2); | ||
| 539 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 540 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 541 | cmd_buff[3] = buff_addr; | ||
| 542 | |||
| 543 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 544 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 545 | unk_param1, translation, buff_addr, buff_size); | ||
| 546 | } | ||
| 547 | |||
| 548 | void GetTaskFinishHandle(Service::Interface* self) { | ||
| 549 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 550 | |||
| 551 | cmd_buff[0] = IPC::MakeHeader(0x1F, 0x1, 0x2); | ||
| 552 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 553 | cmd_buff[2] = 0; | ||
| 554 | cmd_buff[3] = 0; // stub 0(This should be a handle of task_finish ?) | ||
| 555 | |||
| 556 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 557 | } | ||
| 558 | |||
| 559 | void GetTaskState(Service::Interface* self) { | ||
| 560 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 561 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 562 | u32 buff_size = cmd_buff[1]; | ||
| 563 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 564 | u32 translation = cmd_buff[3]; | ||
| 565 | u32 buff_addr = cmd_buff[4]; | ||
| 566 | |||
| 567 | cmd_buff[0] = IPC::MakeHeader(0x20, 0x4, 0x2); | ||
| 568 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 569 | cmd_buff[2] = 0; // stub 0 (8 bit value) | ||
| 570 | cmd_buff[3] = 0; // stub 0 (32 bit value) | ||
| 571 | cmd_buff[4] = 0; // stub 0 (8 bit value) | ||
| 572 | cmd_buff[5] = (buff_size << 4 | 0xA); | ||
| 573 | cmd_buff[6] = buff_addr; | ||
| 574 | |||
| 575 | LOG_WARNING(Service_BOSS, "(STUBBED) buff_size=0x%08X, unk_param2=0x%08X, " | ||
| 576 | "translation=0x%08X, buff_addr=0x%08X", | ||
| 577 | buff_size, unk_param2, translation, buff_addr); | ||
| 578 | } | ||
| 579 | |||
| 580 | void GetTaskResult(Service::Interface* self) { | ||
| 581 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 582 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 583 | u32 unk_param1 = cmd_buff[1]; | ||
| 584 | u32 translation = cmd_buff[2]; | ||
| 585 | u32 buff_addr = cmd_buff[3]; | ||
| 586 | u32 buff_size = (translation >> 4); | ||
| 587 | |||
| 588 | cmd_buff[0] = IPC::MakeHeader(0x21, 0x4, 0x2); | ||
| 589 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 590 | cmd_buff[2] = 0; // stub 0 (8 bit value) | ||
| 591 | cmd_buff[3] = 0; // stub 0 (32 bit value) | ||
| 592 | cmd_buff[4] = 0; // stub 0 (8 bit value) | ||
| 593 | cmd_buff[5] = (buff_size << 4 | 0xA); | ||
| 594 | cmd_buff[6] = buff_addr; | ||
| 595 | |||
| 596 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 597 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 598 | unk_param1, translation, buff_addr, buff_size); | ||
| 599 | } | ||
| 600 | |||
| 601 | void GetTaskCommErrorCode(Service::Interface* self) { | ||
| 602 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 603 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 604 | u32 unk_param1 = cmd_buff[1]; | ||
| 605 | u32 translation = cmd_buff[2]; | ||
| 606 | u32 buff_addr = cmd_buff[3]; | ||
| 607 | u32 buff_size = (translation >> 4); | ||
| 608 | |||
| 609 | cmd_buff[0] = IPC::MakeHeader(0x22, 0x4, 0x2); | ||
| 610 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 611 | cmd_buff[2] = 0; // stub 0 (32 bit value) | ||
| 612 | cmd_buff[3] = 0; // stub 0 (32 bit value) | ||
| 613 | cmd_buff[4] = 0; // stub 0 (8 bit value) | ||
| 614 | cmd_buff[5] = (buff_size << 4 | 0xA); | ||
| 615 | cmd_buff[6] = buff_addr; | ||
| 616 | |||
| 617 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, translation=0x%08X, " | ||
| 618 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 619 | unk_param1, translation, buff_addr, buff_size); | ||
| 620 | } | ||
| 621 | |||
| 622 | void GetTaskStatus(Service::Interface* self) { | ||
| 623 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 624 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 625 | u32 unk_param1 = cmd_buff[1]; | ||
| 626 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 627 | u32 unk_param3 = cmd_buff[3] & 0xFF; | ||
| 628 | u32 translation = cmd_buff[4]; | ||
| 629 | u32 buff_addr = cmd_buff[5]; | ||
| 630 | u32 buff_size = (translation >> 4); | ||
| 631 | |||
| 632 | cmd_buff[0] = IPC::MakeHeader(0x23, 0x2, 0x2); | ||
| 633 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 634 | cmd_buff[2] = 0; // stub 0 (8 bit value) | ||
| 635 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 636 | cmd_buff[4] = buff_addr; | ||
| 637 | |||
| 638 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 639 | "translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 640 | unk_param1, unk_param2, unk_param3, translation, buff_addr, buff_size); | ||
| 641 | } | ||
| 642 | |||
| 643 | void GetTaskError(Service::Interface* self) { | ||
| 644 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 645 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 646 | u32 unk_param1 = cmd_buff[1]; | ||
| 647 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 648 | u32 translation = cmd_buff[4]; | ||
| 649 | u32 buff_addr = cmd_buff[5]; | ||
| 650 | u32 buff_size = (translation >> 4); | ||
| 651 | |||
| 652 | cmd_buff[0] = IPC::MakeHeader(0x24, 0x2, 0x2); | ||
| 653 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 654 | cmd_buff[2] = 0; // stub 0 (8 bit value) | ||
| 655 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 656 | cmd_buff[4] = buff_addr; | ||
| 657 | |||
| 658 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, translation=0x%08X, " | ||
| 659 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 660 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 661 | } | ||
| 662 | |||
| 663 | void GetTaskInfo(Service::Interface* self) { | ||
| 664 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 665 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 666 | u32 unk_param1 = cmd_buff[1]; | ||
| 667 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 668 | u32 translation = cmd_buff[4]; | ||
| 669 | u32 buff_addr = cmd_buff[5]; | ||
| 670 | u32 buff_size = (translation >> 4); | ||
| 671 | |||
| 672 | cmd_buff[0] = IPC::MakeHeader(0x25, 0x1, 0x2); | ||
| 673 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 674 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 675 | cmd_buff[3] = buff_addr; | ||
| 676 | |||
| 677 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, translation=0x%08X, " | ||
| 678 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 679 | unk_param1, unk_param2, translation, buff_addr, buff_size); | ||
| 680 | } | ||
| 681 | |||
| 682 | void DeleteNsData(Service::Interface* self) { | ||
| 683 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 684 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 685 | u32 unk_param1 = cmd_buff[1]; | ||
| 686 | |||
| 687 | cmd_buff[0] = IPC::MakeHeader(0x26, 0x1, 0); | ||
| 688 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 689 | |||
| 690 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X", unk_param1); | ||
| 691 | } | ||
| 692 | |||
| 693 | void GetNsDataHeaderInfo(Service::Interface* self) { | ||
| 694 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 695 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 696 | u32 unk_param1 = cmd_buff[1]; | ||
| 697 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 698 | u32 unk_param3 = cmd_buff[3]; | ||
| 699 | u32 translation = cmd_buff[4]; | ||
| 700 | u32 buff_addr = cmd_buff[5]; | ||
| 701 | u32 buff_size = (translation >> 4); | ||
| 702 | |||
| 703 | cmd_buff[0] = IPC::MakeHeader(0x27, 0x1, 0x2); | ||
| 704 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 705 | cmd_buff[2] = (buff_size << 4 | 0xC); | ||
| 706 | cmd_buff[3] = buff_addr; | ||
| 707 | |||
| 708 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 709 | "translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 710 | unk_param1, unk_param2, unk_param3, translation, buff_addr, buff_size); | ||
| 711 | } | ||
| 712 | |||
| 713 | void ReadNsData(Service::Interface* self) { | ||
| 714 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 715 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 716 | u32 unk_param1 = cmd_buff[1]; | ||
| 717 | u32 unk_param2 = cmd_buff[2]; | ||
| 718 | u32 unk_param3 = cmd_buff[3]; | ||
| 719 | u32 unk_param4 = cmd_buff[4]; | ||
| 720 | u32 translation = cmd_buff[5]; | ||
| 721 | u32 buff_addr = cmd_buff[6]; | ||
| 722 | u32 buff_size = (translation >> 4); | ||
| 723 | |||
| 724 | cmd_buff[0] = IPC::MakeHeader(0x28, 0x3, 0x2); | ||
| 725 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 726 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 727 | cmd_buff[3] = 0; // stub 0 (32bit value) | ||
| 728 | cmd_buff[4] = (buff_size << 4 | 0xC); | ||
| 729 | cmd_buff[5] = buff_addr; | ||
| 730 | |||
| 731 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 732 | "unk_param4=0x%08X, translation=0x%08X, " | ||
| 733 | "buff_addr=0x%08X, buff_size=0x%08X", | ||
| 734 | unk_param1, unk_param2, unk_param3, unk_param4, translation, buff_addr, buff_size); | ||
| 735 | } | ||
| 736 | |||
| 737 | void SetNsDataAdditionalInfo(Service::Interface* self) { | ||
| 738 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 739 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 740 | u32 unk_param1 = cmd_buff[1]; | ||
| 741 | u32 unk_param2 = cmd_buff[2]; | ||
| 742 | |||
| 743 | cmd_buff[0] = IPC::MakeHeader(0x29, 0x1, 0); | ||
| 744 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 745 | |||
| 746 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X", unk_param1, | ||
| 747 | unk_param2); | ||
| 748 | } | ||
| 749 | |||
| 750 | void GetNsDataAdditionalInfo(Service::Interface* self) { | ||
| 751 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 752 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 753 | u32 unk_param1 = cmd_buff[1]; | ||
| 754 | |||
| 755 | cmd_buff[0] = IPC::MakeHeader(0x2A, 0x2, 0); | ||
| 756 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 757 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 758 | |||
| 759 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X", unk_param1); | ||
| 760 | } | ||
| 761 | |||
| 762 | void SetNsDataNewFlag(Service::Interface* self) { | ||
| 763 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 764 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 765 | u32 unk_param1 = cmd_buff[1]; | ||
| 766 | ns_data_new_flag = cmd_buff[2] & 0xFF; | ||
| 767 | |||
| 768 | cmd_buff[0] = IPC::MakeHeader(0x2B, 0x1, 0); | ||
| 769 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 770 | |||
| 771 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, ns_data_new_flag=0x%08X", unk_param1, | ||
| 772 | ns_data_new_flag); | ||
| 773 | } | ||
| 774 | |||
| 775 | void GetNsDataNewFlag(Service::Interface* self) { | ||
| 776 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 777 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 778 | u32 unk_param1 = cmd_buff[1]; | ||
| 779 | |||
| 780 | cmd_buff[0] = IPC::MakeHeader(0x2C, 0x2, 0); | ||
| 781 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 782 | cmd_buff[2] = ns_data_new_flag; | ||
| 783 | |||
| 784 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, ns_data_new_flag=0x%08X", unk_param1, | ||
| 785 | ns_data_new_flag); | ||
| 786 | } | ||
| 787 | |||
| 788 | void GetNsDataLastUpdate(Service::Interface* self) { | ||
| 789 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 790 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 791 | u32 unk_param1 = cmd_buff[1]; | ||
| 792 | |||
| 793 | cmd_buff[0] = IPC::MakeHeader(0x2D, 0x3, 0); | ||
| 794 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 795 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 796 | cmd_buff[3] = 0; // stub 0 (32bit value) | ||
| 797 | |||
| 798 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X", unk_param1); | ||
| 799 | } | ||
| 800 | |||
| 801 | void GetErrorCode(Service::Interface* self) { | ||
| 802 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 803 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 804 | u32 unk_param1 = cmd_buff[1]; | ||
| 805 | |||
| 806 | cmd_buff[0] = IPC::MakeHeader(0x2E, 0x2, 0); | ||
| 807 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 808 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 809 | |||
| 810 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X", unk_param1); | ||
| 811 | } | ||
| 812 | |||
| 813 | void RegisterStorageEntry(Service::Interface* self) { | ||
| 814 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 815 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 816 | u32 unk_param1 = cmd_buff[1]; | ||
| 817 | u32 unk_param2 = cmd_buff[2]; | ||
| 818 | u32 unk_param3 = cmd_buff[3]; | ||
| 819 | u32 unk_param4 = cmd_buff[4]; | ||
| 820 | u32 unk_param5 = cmd_buff[5] & 0xFF; | ||
| 821 | |||
| 822 | cmd_buff[0] = IPC::MakeHeader(0x2F, 0x1, 0); | ||
| 823 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 824 | |||
| 825 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 826 | "unk_param4=0x%08X, unk_param5=0x%08X", | ||
| 827 | unk_param1, unk_param2, unk_param3, unk_param4, unk_param5); | ||
| 828 | } | ||
| 829 | |||
| 830 | void GetStorageEntryInfo(Service::Interface* self) { | ||
| 831 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 832 | |||
| 833 | cmd_buff[0] = IPC::MakeHeader(0x30, 0x3, 0); | ||
| 834 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 835 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 836 | cmd_buff[3] = 0; // stub 0 (16bit value) | ||
| 837 | |||
| 838 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 839 | } | ||
| 840 | |||
| 841 | void SetStorageOption(Service::Interface* self) { | ||
| 842 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 843 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 844 | u32 unk_param1 = cmd_buff[1] & 0xFF; | ||
| 845 | u32 unk_param2 = cmd_buff[2]; | ||
| 846 | u32 unk_param3 = cmd_buff[3]; | ||
| 847 | u32 unk_param4 = cmd_buff[4]; | ||
| 848 | |||
| 849 | cmd_buff[0] = IPC::MakeHeader(0x31, 0x1, 0); | ||
| 850 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 851 | |||
| 852 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, " | ||
| 853 | "unk_param3=0x%08X, unk_param4=0x%08X", | ||
| 854 | unk_param1, unk_param2, unk_param3, unk_param4); | ||
| 855 | } | ||
| 856 | |||
| 857 | void GetStorageOption(Service::Interface* self) { | ||
| 858 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 859 | |||
| 860 | cmd_buff[0] = IPC::MakeHeader(0x32, 0x5, 0); | ||
| 861 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 862 | cmd_buff[2] = 0; // stub 0 (32bit value) | ||
| 863 | cmd_buff[3] = 0; // stub 0 (8bit value) | ||
| 864 | cmd_buff[4] = 0; // stub 0 (16bit value) | ||
| 865 | cmd_buff[5] = 0; // stub 0 (16bit value) | ||
| 866 | |||
| 867 | LOG_WARNING(Service_BOSS, "(STUBBED) called"); | ||
| 868 | } | ||
| 869 | |||
| 870 | void StartBgImmediate(Service::Interface* self) { | ||
| 871 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 872 | |||
| 873 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 874 | u32 translation = cmd_buff[2]; | ||
| 875 | u32 buff_addr = cmd_buff[3]; | ||
| 876 | u32 buff_size = (translation >> 4); | ||
| 877 | |||
| 878 | cmd_buff[0] = IPC::MakeHeader(0x33, 0x1, 0x2); | ||
| 879 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 880 | cmd_buff[2] = (buff_size << 4 | 0xA); | ||
| 881 | cmd_buff[3] = buff_addr; | ||
| 882 | |||
| 883 | LOG_WARNING(Service_BOSS, "(STUBBED) buff_size=0x%08X, unk_param2=0x%08X, " | ||
| 884 | "translation=0x%08X, buff_addr=0x%08X", | ||
| 885 | unk_param1, translation, buff_addr, buff_size); | ||
| 886 | } | ||
| 887 | |||
| 888 | void GetTaskActivePriority(Service::Interface* self) { | ||
| 889 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 890 | |||
| 891 | u32 unk_param1 = cmd_buff[1]; // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 892 | u32 translation = cmd_buff[2]; | ||
| 893 | u32 buff_addr = cmd_buff[3]; | ||
| 894 | u32 buff_size = (translation >> 4); | ||
| 895 | |||
| 896 | cmd_buff[0] = IPC::MakeHeader(0x34, 0x2, 0x2); | ||
| 897 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 898 | cmd_buff[2] = 0; // stub 0 (8bit value) | ||
| 899 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 900 | cmd_buff[4] = buff_addr; | ||
| 901 | |||
| 902 | LOG_WARNING(Service_BOSS, "(STUBBED) buff_size=0x%08X, unk_param2=0x%08X, " | ||
| 903 | "translation=0x%08X, buff_addr=0x%08X", | ||
| 904 | unk_param1, translation, buff_addr, buff_size); | ||
| 905 | } | ||
| 906 | |||
| 907 | void RegisterImmediateTask(Service::Interface* self) { | ||
| 908 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 909 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 910 | u32 unk_param1 = cmd_buff[1]; | ||
| 911 | u32 unk_param2 = cmd_buff[2] & 0xFF; | ||
| 912 | u32 unk_param3 = cmd_buff[3] & 0xFF; | ||
| 913 | u32 translation = cmd_buff[4]; | ||
| 914 | u32 buff_addr = cmd_buff[5]; | ||
| 915 | u32 buff_size = (translation >> 4); | ||
| 916 | |||
| 917 | cmd_buff[0] = IPC::MakeHeader(0x35, 0x1, 0x2); | ||
| 918 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 919 | cmd_buff[3] = (buff_size << 4 | 0xA); | ||
| 920 | cmd_buff[4] = buff_addr; | ||
| 921 | |||
| 922 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, unk_param3=0x%08X, " | ||
| 923 | "translation=0x%08X, buff_addr=0x%08X, buff_size=0x%08X", | ||
| 924 | unk_param1, unk_param2, unk_param3, translation, buff_addr, buff_size); | ||
| 925 | } | ||
| 926 | |||
| 927 | void SetTaskQuery(Service::Interface* self) { | ||
| 928 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 929 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 930 | u32 unk_param1 = cmd_buff[1]; | ||
| 931 | u32 unk_param2 = cmd_buff[2]; | ||
| 932 | u32 translation1 = cmd_buff[3]; | ||
| 933 | u32 buff1_addr = cmd_buff[4]; | ||
| 934 | u32 buff1_size = (translation1 >> 4); | ||
| 935 | u32 translation2 = cmd_buff[5]; | ||
| 936 | u32 buff2_addr = cmd_buff[6]; | ||
| 937 | u32 buff2_size = (translation2 >> 4); | ||
| 938 | |||
| 939 | cmd_buff[0] = IPC::MakeHeader(0x36, 0x1, 0x4); | ||
| 940 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 941 | cmd_buff[2] = (buff1_size << 4 | 0xA); | ||
| 942 | cmd_buff[3] = buff1_addr; | ||
| 943 | cmd_buff[2] = (buff2_size << 4 | 0xA); | ||
| 944 | cmd_buff[3] = buff2_addr; | ||
| 945 | |||
| 946 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, " | ||
| 947 | "translation1=0x%08X, buff1_addr=0x%08X, buff1_size=0x%08X, " | ||
| 948 | "translation2=0x%08X, buff2_addr=0x%08X, buff2_size=0x%08X", | ||
| 949 | unk_param1, unk_param2, translation1, buff1_addr, buff1_size, translation2, | ||
| 950 | buff2_addr, buff2_size); | ||
| 951 | } | ||
| 952 | |||
| 953 | void GetTaskQuery(Service::Interface* self) { | ||
| 954 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 955 | // TODO(JamePeng): Figure out the meaning of these parameters | ||
| 956 | u32 unk_param1 = cmd_buff[1]; | ||
| 957 | u32 unk_param2 = cmd_buff[2]; | ||
| 958 | u32 translation1 = cmd_buff[3]; | ||
| 959 | u32 buff1_addr = cmd_buff[4]; | ||
| 960 | u32 buff1_size = (translation1 >> 4); | ||
| 961 | u32 translation2 = cmd_buff[5]; | ||
| 962 | u32 buff2_addr = cmd_buff[6]; | ||
| 963 | u32 buff2_size = (translation2 >> 4); | ||
| 964 | |||
| 965 | cmd_buff[0] = IPC::MakeHeader(0x37, 0x1, 0x4); | ||
| 966 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 967 | cmd_buff[2] = (buff1_size << 4 | 0xA); | ||
| 968 | cmd_buff[3] = buff1_addr; | ||
| 969 | cmd_buff[2] = (buff2_size << 4 | 0xC); | ||
| 970 | cmd_buff[3] = buff2_addr; | ||
| 971 | |||
| 972 | LOG_WARNING(Service_BOSS, "(STUBBED) unk_param1=0x%08X, unk_param2=0x%08X, " | ||
| 973 | "translation1=0x%08X, buff1_addr=0x%08X, buff1_size=0x%08X, " | ||
| 974 | "translation2=0x%08X, buff2_addr=0x%08X, buff2_size=0x%08X", | ||
| 975 | unk_param1, unk_param2, translation1, buff1_addr, buff1_size, translation2, | ||
| 976 | buff2_addr, buff2_size); | ||
| 977 | } | ||
| 978 | |||
| 979 | void Init() { | ||
| 980 | using namespace Kernel; | ||
| 981 | |||
| 982 | AddService(new BOSS_P_Interface); | ||
| 983 | AddService(new BOSS_U_Interface); | ||
| 984 | |||
| 985 | new_arrival_flag = 0; | ||
| 986 | ns_data_new_flag = 0; | ||
| 987 | output_flag = 0; | ||
| 988 | } | ||
| 989 | |||
| 990 | void Shutdown() {} | ||
| 991 | |||
| 992 | } // namespace BOSS | ||
| 993 | |||
| 994 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h deleted file mode 100644 index 8cdc663c8..000000000 --- a/src/core/hle/service/boss/boss.h +++ /dev/null | |||
| @@ -1,802 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace BOSS { | ||
| 11 | |||
| 12 | /** | ||
| 13 | * BOSS::InitializeSession service function | ||
| 14 | * Inputs: | ||
| 15 | * 0 : Header Code[0x00010082] | ||
| 16 | * 1 : u32 lower 64bit value | ||
| 17 | * 2 : u32 higher 64bit value | ||
| 18 | * 3 : 0x20 | ||
| 19 | * 4 : u32 unknown value | ||
| 20 | * Outputs: | ||
| 21 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 22 | */ | ||
| 23 | void InitializeSession(Service::Interface* self); | ||
| 24 | |||
| 25 | /** | ||
| 26 | * BOSS::RegisterStorage service function | ||
| 27 | * Inputs: | ||
| 28 | * 0 : Header Code[0x00020010] | ||
| 29 | * 1 : u32 unknown1 | ||
| 30 | * 2 : u32 unknown2 | ||
| 31 | * 3 : u32 unknown3 | ||
| 32 | * 4 : u8 unknown_flag | ||
| 33 | * Outputs: | ||
| 34 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 35 | */ | ||
| 36 | void RegisterStorage(Service::Interface* self); | ||
| 37 | |||
| 38 | /** | ||
| 39 | * BOSS::UnregisterStorage service function | ||
| 40 | * Inputs: | ||
| 41 | * 0 : Header Code[0x00030000] | ||
| 42 | * Outputs: | ||
| 43 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 44 | */ | ||
| 45 | void UnregisterStorage(Service::Interface* self); | ||
| 46 | |||
| 47 | /** | ||
| 48 | * BOSS::GetStorageInfo service function | ||
| 49 | * Inputs: | ||
| 50 | * 0 : Header Code[0x00040000] | ||
| 51 | * Outputs: | ||
| 52 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 53 | * 2 : u32 unknown value | ||
| 54 | */ | ||
| 55 | void GetStorageInfo(Service::Interface* self); | ||
| 56 | |||
| 57 | /** | ||
| 58 | * BOSS::RegisterPrivateRootCa service function | ||
| 59 | * Inputs: | ||
| 60 | * 0 : Header Code[0x00050042] | ||
| 61 | * 1 : u32 unknown value | ||
| 62 | * 2 : MappedBufferDesc(permission = R) | ||
| 63 | * 3 : u32 buff_addr | ||
| 64 | * Outputs: | ||
| 65 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 66 | * 2 : buff_size << 4 | 0xA | ||
| 67 | * 3 : u32 buff_addr | ||
| 68 | */ | ||
| 69 | void RegisterPrivateRootCa(Service::Interface* self); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * BOSS::RegisterPrivateClientCert service function | ||
| 73 | * Inputs: | ||
| 74 | * 0 : Header Code[0x00060084] | ||
| 75 | * 1 : u32 unknown value | ||
| 76 | * 2 : u32 unknown value | ||
| 77 | * 3 : MappedBufferDesc1(permission = R) | ||
| 78 | * 4 : u32 buff_addr1 | ||
| 79 | * 5 : MappedBufferDesc2(permission = R) | ||
| 80 | * 6 : u32 buff_addr2 | ||
| 81 | * Outputs: | ||
| 82 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 83 | * 2 : buff1_size << 4 | 0xA | ||
| 84 | * 3 : u32 buff_addr1 | ||
| 85 | * 4 : buff2_size << 4 | 0xA | ||
| 86 | * 5 : u32 buff_addr2 | ||
| 87 | */ | ||
| 88 | void RegisterPrivateClientCert(Service::Interface* self); | ||
| 89 | |||
| 90 | /** | ||
| 91 | * BOSS::GetNewArrivalFlag service function | ||
| 92 | * Inputs: | ||
| 93 | * 0 : Header Code[0x00070000] | ||
| 94 | * Outputs: | ||
| 95 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 96 | * 2 : u8 flag | ||
| 97 | */ | ||
| 98 | void GetNewArrivalFlag(Service::Interface* self); | ||
| 99 | |||
| 100 | /** | ||
| 101 | * BOSS::RegisterNewArrivalEvent service function | ||
| 102 | * Inputs: | ||
| 103 | * 0 : Header Code[0x00080002] | ||
| 104 | * 1 : u32 unknown1 | ||
| 105 | * 2 : u32 unknown2 | ||
| 106 | * Outputs: | ||
| 107 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 108 | */ | ||
| 109 | void RegisterNewArrivalEvent(Service::Interface* self); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * BOSS::SetOptoutFlag service function | ||
| 113 | * Inputs: | ||
| 114 | * 0 : Header Code[0x00090040] | ||
| 115 | * 1 : u8 output_flag | ||
| 116 | * Outputs: | ||
| 117 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 118 | */ | ||
| 119 | void SetOptoutFlag(Service::Interface* self); | ||
| 120 | |||
| 121 | /** | ||
| 122 | * BOSS::GetOptoutFlag service function | ||
| 123 | * Inputs: | ||
| 124 | * 0 : Header Code[0x000A0000] | ||
| 125 | * Outputs: | ||
| 126 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 127 | * 2 : u8 output_flag | ||
| 128 | */ | ||
| 129 | void GetOptoutFlag(Service::Interface* self); | ||
| 130 | |||
| 131 | /** | ||
| 132 | * BOSS::RegisterTask service function | ||
| 133 | * Inputs: | ||
| 134 | * 0 : Header Code[0x000B00C2] | ||
| 135 | * 1 : u32 unknown value | ||
| 136 | * 2 : u8 unknown value | ||
| 137 | * 3 : u8 unknown value | ||
| 138 | * 4 : MappedBufferDesc1(permission = R) | ||
| 139 | * 5 : buff_addr | ||
| 140 | * Outputs: | ||
| 141 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 142 | * 2 : buff_size << 4 | 0xA | ||
| 143 | * 3 : u32 buff_addr | ||
| 144 | */ | ||
| 145 | void RegisterTask(Service::Interface* self); | ||
| 146 | |||
| 147 | /** | ||
| 148 | * BOSS::UnregisterTask service function | ||
| 149 | * Inputs: | ||
| 150 | * 0 : Header Code[0x000C0082] | ||
| 151 | * 1 : u32 unknown value | ||
| 152 | * 2 : u8 unknown value | ||
| 153 | * 3 : MappedBufferDesc1(permission = R) | ||
| 154 | * 4 : buff_addr | ||
| 155 | * Outputs: | ||
| 156 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 157 | * 2 : buff_size << 4 | 0xA | ||
| 158 | * 3 : u32 buff_addr | ||
| 159 | */ | ||
| 160 | void UnregisterTask(Service::Interface* self); | ||
| 161 | |||
| 162 | /** | ||
| 163 | * BOSS::ReconfigureTask service function | ||
| 164 | * Inputs: | ||
| 165 | * 0 : Header Code[0x000D0082] | ||
| 166 | * 1 : u32 unknown value | ||
| 167 | * 2 : u8 unknown value | ||
| 168 | * 3 : MappedBufferDesc1(permission = R) | ||
| 169 | * 4 : buff_addr | ||
| 170 | * Outputs: | ||
| 171 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 172 | * 2 : buff_size << 4 | 0xA | ||
| 173 | * 3 : u32 buff_addr | ||
| 174 | */ | ||
| 175 | void ReconfigureTask(Service::Interface* self); | ||
| 176 | |||
| 177 | /** | ||
| 178 | * BOSS::GetTaskIdList service function | ||
| 179 | * Inputs: | ||
| 180 | * 0 : Header Code[0x000E0000] | ||
| 181 | * Outputs: | ||
| 182 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 183 | */ | ||
| 184 | void GetTaskIdList(Service::Interface* self); | ||
| 185 | |||
| 186 | /** | ||
| 187 | * BOSS::GetStepIdList service function | ||
| 188 | * Inputs: | ||
| 189 | * 0 : Header Code[0x000F0042] | ||
| 190 | * 2 : MappedBufferDesc(permission = R) | ||
| 191 | * 3 : u32 buff_addr | ||
| 192 | * | ||
| 193 | * Outputs: | ||
| 194 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 195 | * 2 : buff_size << 4 | 0xA | ||
| 196 | * 3 : u32 buff_addr | ||
| 197 | */ | ||
| 198 | void GetStepIdList(Service::Interface* self); | ||
| 199 | |||
| 200 | /** | ||
| 201 | * BOSS::GetNsDataIdList service function | ||
| 202 | * Inputs: | ||
| 203 | * 0 : Header Code[0x00100102] | ||
| 204 | * 1 : u32 unknown1 | ||
| 205 | * 2 : u32 unknown2 | ||
| 206 | * 3 : u32 unknown3 | ||
| 207 | * 4 : u32 unknown4 | ||
| 208 | * 5 : MappedBufferDesc(permission = W) | ||
| 209 | * 6 : u32 buff_addr | ||
| 210 | * Outputs: | ||
| 211 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 212 | * 2 : u16 unknown value | ||
| 213 | * 3 : u16 unknown value | ||
| 214 | * 4 : buff_size << 4 | 0xC | ||
| 215 | * 5 : u32 buff_addr | ||
| 216 | */ | ||
| 217 | void GetNsDataIdList(Service::Interface* self); | ||
| 218 | |||
| 219 | /** | ||
| 220 | * BOSS::GetOwnNsDataIdList service function | ||
| 221 | * Inputs: | ||
| 222 | * 0 : Header Code[0x00110102] | ||
| 223 | * 1 : u32 unknown1 | ||
| 224 | * 2 : u32 unknown2 | ||
| 225 | * 3 : u32 unknown3 | ||
| 226 | * 4 : u32 unknown4 | ||
| 227 | * 5 : MappedBufferDesc(permission = W) | ||
| 228 | * 6 : u32 buff_addr | ||
| 229 | * Outputs: | ||
| 230 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 231 | * 2 : u16 unknown value | ||
| 232 | * 3 : u16 unknown value | ||
| 233 | * 4 : buff_size << 4 | 0xC | ||
| 234 | * 5 : u32 buff_addr | ||
| 235 | */ | ||
| 236 | void GetOwnNsDataIdList(Service::Interface* self); | ||
| 237 | |||
| 238 | /** | ||
| 239 | * BOSS::GetNewDataNsDataIdList service function | ||
| 240 | * Inputs: | ||
| 241 | * 0 : Header Code[0x00120102] | ||
| 242 | * 1 : u32 unknown1 | ||
| 243 | * 2 : u32 unknown2 | ||
| 244 | * 3 : u32 unknown3 | ||
| 245 | * 4 : u32 unknown4 | ||
| 246 | * 5 : MappedBufferDesc(permission = W) | ||
| 247 | * 6 : u32 buff_addr | ||
| 248 | * Outputs: | ||
| 249 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 250 | * 2 : u16 unknown value | ||
| 251 | * 3 : u16 unknown value | ||
| 252 | * 4 : buff_size << 4 | 0xC | ||
| 253 | * 5 : u32 buff_addr | ||
| 254 | */ | ||
| 255 | void GetNewDataNsDataIdList(Service::Interface* self); | ||
| 256 | |||
| 257 | /** | ||
| 258 | * BOSS::GetOwnNewDataNsDataIdList service function | ||
| 259 | * Inputs: | ||
| 260 | * 0 : Header Code[0x00130102] | ||
| 261 | * 1 : u32 unknown1 | ||
| 262 | * 2 : u32 unknown2 | ||
| 263 | * 3 : u32 unknown3 | ||
| 264 | * 4 : u32 unknown4 | ||
| 265 | * 5 : MappedBufferDesc(permission = W) | ||
| 266 | * 6 : u32 buff_addr | ||
| 267 | * Outputs: | ||
| 268 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 269 | * 2 : u16 unknown value | ||
| 270 | * 3 : u16 unknown value | ||
| 271 | |||
| 272 | */ | ||
| 273 | void GetOwnNewDataNsDataIdList(Service::Interface* self); | ||
| 274 | |||
| 275 | /** | ||
| 276 | * BOSS::SendProperty service function | ||
| 277 | * Inputs: | ||
| 278 | * 0 : Header Code[0x00140082] | ||
| 279 | * 1 : u16 unknown value | ||
| 280 | * 2 : u32 unknown value | ||
| 281 | * 3 : MappedBufferDesc(permission = R) | ||
| 282 | * 4 : u32 buff_addr | ||
| 283 | * Outputs: | ||
| 284 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 285 | * 2 : buff_size << 4 | 0xA | ||
| 286 | * 3 : u32 buff_addr | ||
| 287 | */ | ||
| 288 | void SendProperty(Service::Interface* self); | ||
| 289 | |||
| 290 | /** | ||
| 291 | * BOSS::SendPropertyHandle service function | ||
| 292 | * Inputs: | ||
| 293 | * 0 : Header Code[0x00150042] | ||
| 294 | * 2 : u8 unknown value | ||
| 295 | * 3 : MappedBufferDesc(permission = R) | ||
| 296 | * 4 : u32 buff_addr | ||
| 297 | * Outputs: | ||
| 298 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 299 | * 2 : buff_size << 4 | 0xA | ||
| 300 | * 3 : u32 buff_addr | ||
| 301 | */ | ||
| 302 | void SendPropertyHandle(Service::Interface* self); | ||
| 303 | |||
| 304 | /** | ||
| 305 | * BOSS::ReceiveProperty service function | ||
| 306 | * Inputs: | ||
| 307 | * 0 : Header Code[0x00160082] | ||
| 308 | * 1 : u16 unknown1 | ||
| 309 | * 2 : u32 buff_size | ||
| 310 | * 3 : MappedBufferDesc(permission = W) | ||
| 311 | * 4 : u32 buff addr | ||
| 312 | * Outputs: | ||
| 313 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 314 | * 2 : u32 unknown value | ||
| 315 | * 3 : u16 unknown value | ||
| 316 | * 4 : buff_size << 4 | 0xC | ||
| 317 | * 5 : u32 buff_addr | ||
| 318 | */ | ||
| 319 | void ReceiveProperty(Service::Interface* self); | ||
| 320 | |||
| 321 | /** | ||
| 322 | * BOSS::UpdateTaskInterval service function | ||
| 323 | * Inputs: | ||
| 324 | * 0 : Header Code[0x00170082] | ||
| 325 | * 1 : u32 unknown value | ||
| 326 | * 2 : u8 unknown value | ||
| 327 | * 3 : MappedBufferDesc1(permission = R) | ||
| 328 | * 4 : buff_addr | ||
| 329 | * Outputs: | ||
| 330 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 331 | * 2 : buff_size << 4 | 0xA | ||
| 332 | * 3 : u32 buff_addr | ||
| 333 | */ | ||
| 334 | void UpdateTaskInterval(Service::Interface* self); | ||
| 335 | |||
| 336 | /** | ||
| 337 | * BOSS::UpdateTaskCount service function | ||
| 338 | * Inputs: | ||
| 339 | * 0 : Header Code[0x00180082] | ||
| 340 | * 1 : u32 buff_size | ||
| 341 | * 2 : u32 unknown2 | ||
| 342 | * 3 : MappedBufferDesc(permission = R) | ||
| 343 | * 4 : u32 buff_addr | ||
| 344 | * Outputs: | ||
| 345 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 346 | * 2 : buff_size << 4 | 0xA | ||
| 347 | * 3 : u32 buff_addr | ||
| 348 | */ | ||
| 349 | void UpdateTaskCount(Service::Interface* self); | ||
| 350 | |||
| 351 | /** | ||
| 352 | * BOSS::GetTaskInterval service function | ||
| 353 | * Inputs: | ||
| 354 | * 0 : Header Code[0x00190042] | ||
| 355 | * 1 : u32 unknown value | ||
| 356 | * 2 : MappedBufferDesc(permission = R) | ||
| 357 | * 3 : u32 buff_addr | ||
| 358 | * Outputs: | ||
| 359 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 360 | * 2 : u32 unknown value | ||
| 361 | * 3 : buff_size << 4 | 0xA | ||
| 362 | * 4 : u32 buff_addr | ||
| 363 | */ | ||
| 364 | void GetTaskInterval(Service::Interface* self); | ||
| 365 | |||
| 366 | /** | ||
| 367 | * BOSS::GetTaskCount service function | ||
| 368 | * Inputs: | ||
| 369 | * 0 : Header Code[0x001A0042] | ||
| 370 | * 1 : u32 unknown value | ||
| 371 | * 2 : MappedBufferDesc(permission = R) | ||
| 372 | * 3 : u32 buff_addr | ||
| 373 | * Outputs: | ||
| 374 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 375 | * 2 : u32 unknown value | ||
| 376 | * 3 : buff_size << 4 | 0xA | ||
| 377 | * 4 : u32 buff_addr | ||
| 378 | */ | ||
| 379 | void GetTaskCount(Service::Interface* self); | ||
| 380 | |||
| 381 | /** | ||
| 382 | * BOSS::GetTaskServiceStatus service function | ||
| 383 | * Inputs: | ||
| 384 | * 0 : Header Code[0x001B0042] | ||
| 385 | * 1 : u32 unknown value | ||
| 386 | * 2 : MappedBufferDesc(permission = R) | ||
| 387 | * 3 : u32 buff_addr | ||
| 388 | * Outputs: | ||
| 389 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 390 | * 2 : u8 unknown value | ||
| 391 | * 3 : buff_size << 4 | 0xA | ||
| 392 | * 4 : u32 buff_addr | ||
| 393 | */ | ||
| 394 | void GetTaskServiceStatus(Service::Interface* self); | ||
| 395 | |||
| 396 | /** | ||
| 397 | * BOSS::StartTask service function | ||
| 398 | * Inputs: | ||
| 399 | * 0 : Header Code[0x001C0042] | ||
| 400 | * 1 : u32 unknown value | ||
| 401 | * 2 : MappedBufferDesc(permission = R) | ||
| 402 | * 3 : u32 buff_addr | ||
| 403 | * Outputs: | ||
| 404 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 405 | * 2 : buff_size << 4 | 0xA | ||
| 406 | * 3 : u32 buff_addr | ||
| 407 | */ | ||
| 408 | void StartTask(Service::Interface* self); | ||
| 409 | |||
| 410 | /** | ||
| 411 | * BOSS::StartTaskImmediate service function | ||
| 412 | * Inputs: | ||
| 413 | * 0 : Header Code[0x001D0042] | ||
| 414 | * 1 : u32 unknown value | ||
| 415 | * 2 : MappedBufferDesc(permission = R) | ||
| 416 | * 3 : u32 buff_addr | ||
| 417 | * Outputs: | ||
| 418 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 419 | * 2 : buff_size << 4 | 0xA | ||
| 420 | * 3 : u32 buff_addr | ||
| 421 | */ | ||
| 422 | void StartTaskImmediate(Service::Interface* self); | ||
| 423 | |||
| 424 | /** | ||
| 425 | * BOSS::CancelTask service function | ||
| 426 | * Inputs: | ||
| 427 | * 0 : Header Code[0x001E0042] | ||
| 428 | * 1 : u32 unknown value | ||
| 429 | * 2 : MappedBufferDesc(permission = R) | ||
| 430 | * 3 : u32 buff_addr | ||
| 431 | * Outputs: | ||
| 432 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 433 | * 2 : buff_size << 4 | 0xA | ||
| 434 | * 3 : u32 buff_addr | ||
| 435 | */ | ||
| 436 | void CancelTask(Service::Interface* self); | ||
| 437 | |||
| 438 | /** | ||
| 439 | * BOSS::GetTaskFinishHandle service function | ||
| 440 | * Inputs: | ||
| 441 | * 0 : Header Code[0x001F0000] | ||
| 442 | * Outputs: | ||
| 443 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 444 | * 2 : 0 | ||
| 445 | * 3 : Task Finish Handle | ||
| 446 | */ | ||
| 447 | void GetTaskFinishHandle(Service::Interface* self); | ||
| 448 | |||
| 449 | /** | ||
| 450 | * BOSS::GetTaskState service function | ||
| 451 | * Inputs: | ||
| 452 | * 0 : Header Code[0x00200082] | ||
| 453 | * 1 : u32 buff_size | ||
| 454 | * 2 : u8 unknown value | ||
| 455 | * 3 : MappedBufferDesc(permission = R) | ||
| 456 | * 4 : u32 buff_addr | ||
| 457 | * Outputs: | ||
| 458 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 459 | * 2 : u8 unknown value | ||
| 460 | * 3 : u32 unknown value | ||
| 461 | * 4 : u8 unknown value | ||
| 462 | * 5 : buff_size << 4 | 0xA | ||
| 463 | * 6 : u32 buff_addr | ||
| 464 | */ | ||
| 465 | void GetTaskState(Service::Interface* self); | ||
| 466 | |||
| 467 | /** | ||
| 468 | * BOSS::GetTaskResult service function | ||
| 469 | * Inputs: | ||
| 470 | * 0 : Header Code[0x00210042] | ||
| 471 | * 1 : u32 unknown value | ||
| 472 | * 2 : MappedBufferDesc(permission = R) | ||
| 473 | * 3 : u32 buff_addr | ||
| 474 | * Outputs: | ||
| 475 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 476 | * 2 : u8 unknown value | ||
| 477 | * 3 : u32 unknown value | ||
| 478 | * 4 : u8 unknown value | ||
| 479 | * 5 : buff_size << 4 | 0xA | ||
| 480 | * 6 : u32 buff_addr | ||
| 481 | */ | ||
| 482 | void GetTaskResult(Service::Interface* self); | ||
| 483 | |||
| 484 | /** | ||
| 485 | * BOSS::GetTaskCommErrorCode service function | ||
| 486 | * Inputs: | ||
| 487 | * 0 : Header Code[0x00220042] | ||
| 488 | * 1 : u32 unknown value | ||
| 489 | * 2 : MappedBufferDesc(permission = R) | ||
| 490 | * 3 : u32 buff_addr | ||
| 491 | * Outputs: | ||
| 492 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 493 | * 2 : u32 unknown value | ||
| 494 | * 3 : u32 unknown value | ||
| 495 | * 4 : u8 unknown value | ||
| 496 | * 5 : buff_size << 4 | 0xA | ||
| 497 | * 6 : u32 buff_addr | ||
| 498 | */ | ||
| 499 | void GetTaskCommErrorCode(Service::Interface* self); | ||
| 500 | |||
| 501 | /** | ||
| 502 | * BOSS::GetTaskStatus service function | ||
| 503 | * Inputs: | ||
| 504 | * 0 : Header Code[0x002300C2] | ||
| 505 | * 1 : u32 unknown value | ||
| 506 | * 2 : u8 unknown value | ||
| 507 | * 3 : u8 unknown value | ||
| 508 | * 4 : MappedBufferDesc(permission = R) | ||
| 509 | * 5 : u32 buff_addr | ||
| 510 | * Outputs: | ||
| 511 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 512 | * 2 : u8 unknown value | ||
| 513 | * 3 : buff_size << 4 | 0xA | ||
| 514 | * 4 : u32 buff_addr | ||
| 515 | */ | ||
| 516 | void GetTaskStatus(Service::Interface* self); | ||
| 517 | |||
| 518 | /** | ||
| 519 | * BOSS::GetTaskError service function | ||
| 520 | * Inputs: | ||
| 521 | * 0 : Header Code[0x00240082] | ||
| 522 | * 1 : u32 unknown value | ||
| 523 | * 2 : u8 unknown value | ||
| 524 | * 3 : MappedBufferDesc(permission = R) | ||
| 525 | * 4 : u32 buff_addr | ||
| 526 | * Outputs: | ||
| 527 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 528 | * 2 : u8 unknown value | ||
| 529 | * 3 : buff_size << 4 | 0xA | ||
| 530 | * 4 : u32 buff_addr | ||
| 531 | */ | ||
| 532 | void GetTaskError(Service::Interface* self); | ||
| 533 | |||
| 534 | /** | ||
| 535 | * BOSS::GetTaskInfo service function | ||
| 536 | * Inputs: | ||
| 537 | * 0 : Header Code[0x00250082] | ||
| 538 | * 1 : u32 unknown value | ||
| 539 | * 2 : u8 unknown value | ||
| 540 | * 3 : MappedBufferDesc(permission = R) | ||
| 541 | * 4 : u32 buff_addr | ||
| 542 | * Outputs: | ||
| 543 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 544 | * 2 : buff_size << 4 | 0xA | ||
| 545 | * 3 : u32 buff_addr | ||
| 546 | */ | ||
| 547 | void GetTaskInfo(Service::Interface* self); | ||
| 548 | |||
| 549 | /** | ||
| 550 | * BOSS::DeleteNsData service function | ||
| 551 | * Inputs: | ||
| 552 | * 0 : Header Code[0x00260040] | ||
| 553 | * 1 : u32 unknown value | ||
| 554 | * Outputs: | ||
| 555 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 556 | */ | ||
| 557 | void DeleteNsData(Service::Interface* self); | ||
| 558 | |||
| 559 | /** | ||
| 560 | * BOSS::GetNsDataHeaderInfo service function | ||
| 561 | * Inputs: | ||
| 562 | * 0 : Header Code[0x002700C2] | ||
| 563 | * 1 : u32 unknown value | ||
| 564 | * 2 : u8 unknown value | ||
| 565 | * 3 : u32 unknown value | ||
| 566 | * 4 : MappedBufferDesc(permission = W) | ||
| 567 | * 5 : u32 buff_addr | ||
| 568 | * Outputs: | ||
| 569 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 570 | * 2 : buff_size << 4 | 0xC | ||
| 571 | * 3 : u32 buff_addr | ||
| 572 | */ | ||
| 573 | void GetNsDataHeaderInfo(Service::Interface* self); | ||
| 574 | |||
| 575 | /** | ||
| 576 | * BOSS::ReadNsData service function | ||
| 577 | * Inputs: | ||
| 578 | * 0 : Header Code[0x00280102] | ||
| 579 | * 1 : u32 unknown value | ||
| 580 | * 2 : u32 unknown value | ||
| 581 | * 3 : u32 unknown value | ||
| 582 | * 4 : u32 unknown value | ||
| 583 | * 5 : MappedBufferDesc(permission = W) | ||
| 584 | * 6 : u32 buff_addr | ||
| 585 | * Outputs: | ||
| 586 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 587 | * 2 : u32 unknown value | ||
| 588 | * 3 : u32 unknown value | ||
| 589 | * 4 : buff_size << 4 | 0xC | ||
| 590 | * 5 : u32 buff_addr | ||
| 591 | */ | ||
| 592 | void ReadNsData(Service::Interface* self); | ||
| 593 | |||
| 594 | /** | ||
| 595 | * BOSS::SetNsDataAdditionalInfo service function | ||
| 596 | * Inputs: | ||
| 597 | * 0 : Header Code[0x00290080] | ||
| 598 | * 1 : u32 unknown value | ||
| 599 | * 2 : u32 unknown value | ||
| 600 | * Outputs: | ||
| 601 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 602 | */ | ||
| 603 | void SetNsDataAdditionalInfo(Service::Interface* self); | ||
| 604 | |||
| 605 | /** | ||
| 606 | * BOSS::GetNsDataAdditionalInfo service function | ||
| 607 | * Inputs: | ||
| 608 | * 0 : Header Code[0x002A0040] | ||
| 609 | * 1 : u32 unknown value | ||
| 610 | * Outputs: | ||
| 611 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 612 | * 2 : u32 unknown value | ||
| 613 | */ | ||
| 614 | void GetNsDataAdditionalInfo(Service::Interface* self); | ||
| 615 | |||
| 616 | /** | ||
| 617 | * BOSS::SetNsDataNewFlag service function | ||
| 618 | * Inputs: | ||
| 619 | * 0 : Header Code[0x002B0080] | ||
| 620 | * 1 : u32 unknown value | ||
| 621 | * 2 : u8 flag | ||
| 622 | * Outputs: | ||
| 623 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 624 | */ | ||
| 625 | void SetNsDataNewFlag(Service::Interface* self); | ||
| 626 | |||
| 627 | /** | ||
| 628 | * BOSS::GetNsDataNewFlag service function | ||
| 629 | * Inputs: | ||
| 630 | * 0 : Header Code[0x002C0040] | ||
| 631 | * 1 : u32 unknown value | ||
| 632 | * Outputs: | ||
| 633 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 634 | * 2 : u8 flag | ||
| 635 | */ | ||
| 636 | void GetNsDataNewFlag(Service::Interface* self); | ||
| 637 | |||
| 638 | /** | ||
| 639 | * BOSS::GetNsDataLastUpdate service function | ||
| 640 | * Inputs: | ||
| 641 | * 0 : Header Code[0x002D0040] | ||
| 642 | * 1 : u32 unknown value | ||
| 643 | * Outputs: | ||
| 644 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 645 | * 2 : u32 unknown value | ||
| 646 | * 3 : u32 unknown value | ||
| 647 | */ | ||
| 648 | void GetNsDataLastUpdate(Service::Interface* self); | ||
| 649 | |||
| 650 | /** | ||
| 651 | * BOSS::GetErrorCode service function | ||
| 652 | * Inputs: | ||
| 653 | * 0 : Header Code[0x002E0040] | ||
| 654 | * 1 : u8 unknown value | ||
| 655 | * Outputs: | ||
| 656 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 657 | * 2 : u32 unknown value | ||
| 658 | */ | ||
| 659 | void GetErrorCode(Service::Interface* self); | ||
| 660 | |||
| 661 | /** | ||
| 662 | * BOSS::RegisterStorageEntry service function | ||
| 663 | * Inputs: | ||
| 664 | * 0 : Header Code[0x002F0140] | ||
| 665 | * 1 : u32 unknown value | ||
| 666 | * 2 : u32 unknown value | ||
| 667 | * 3 : u32 unknown value | ||
| 668 | * 4 : u16 unknown value | ||
| 669 | * 5 : u8 unknown value | ||
| 670 | * Outputs: | ||
| 671 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 672 | */ | ||
| 673 | void RegisterStorageEntry(Service::Interface* self); | ||
| 674 | |||
| 675 | /** | ||
| 676 | * BOSS::GetStorageEntryInfo service function | ||
| 677 | * Inputs: | ||
| 678 | * 0 : Header Code[0x00300000] | ||
| 679 | * Outputs: | ||
| 680 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 681 | * 2 : u32 unknown value | ||
| 682 | * 3 : u16 unknown value | ||
| 683 | */ | ||
| 684 | void GetStorageEntryInfo(Service::Interface* self); | ||
| 685 | |||
| 686 | /** | ||
| 687 | * BOSS::SetStorageOption service function | ||
| 688 | * Inputs: | ||
| 689 | * 0 : Header Code[0x00310100] | ||
| 690 | * 1 : u8 unknown value | ||
| 691 | * 2 : u32 unknown value | ||
| 692 | * 3 : u16 unknown value | ||
| 693 | * 4 : u16 unknown value | ||
| 694 | * Outputs: | ||
| 695 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 696 | */ | ||
| 697 | void SetStorageOption(Service::Interface* self); | ||
| 698 | |||
| 699 | /** | ||
| 700 | * BOSS::GetStorageOption service function | ||
| 701 | * Inputs: | ||
| 702 | * 0 : Header Code[0x00320000] | ||
| 703 | * Outputs: | ||
| 704 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 705 | * 2 : u8 unknown value | ||
| 706 | * 3 : u32 unknown value | ||
| 707 | * 4 : u16 unknown value | ||
| 708 | * 5 : u16 unknown value | ||
| 709 | */ | ||
| 710 | void GetStorageOption(Service::Interface* self); | ||
| 711 | |||
| 712 | /** | ||
| 713 | * BOSS::StartBgImmediate service function | ||
| 714 | * Inputs: | ||
| 715 | * 0 : Header Code[0x00330042] | ||
| 716 | * 1 : u32 unknown value | ||
| 717 | * 2 : MappedBufferDesc(permission = R) | ||
| 718 | * 3 : u32 buff_addr | ||
| 719 | * Outputs: | ||
| 720 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 721 | * 2 : buff_size << 4 | 0xA | ||
| 722 | * 3 : u32 buff_addr | ||
| 723 | */ | ||
| 724 | void StartBgImmediate(Service::Interface* self); | ||
| 725 | |||
| 726 | /** | ||
| 727 | * BOSS::GetTaskActivePriority service function | ||
| 728 | * Inputs: | ||
| 729 | * 0 : Header Code[0x00340042] | ||
| 730 | * 1 : u32 unknown value | ||
| 731 | * 2 : MappedBufferDesc(permission = R) | ||
| 732 | * 3 : u32 buff_addr | ||
| 733 | * Outputs: | ||
| 734 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 735 | * 2 : u8 unknown value | ||
| 736 | * 3 : buff_size << 4 | 0xA | ||
| 737 | * 4 : u32 buff_addr | ||
| 738 | */ | ||
| 739 | void GetTaskActivePriority(Service::Interface* self); | ||
| 740 | |||
| 741 | /** | ||
| 742 | * BOSS::RegisterImmediateTask service function | ||
| 743 | * Inputs: | ||
| 744 | * 0 : Header Code[0x003500C2] | ||
| 745 | * 1 : u32 unknown value | ||
| 746 | * 2 : u8 unknown value | ||
| 747 | * 3 : u8 unknown value | ||
| 748 | * 4 : MappedBufferDesc(permission = R) | ||
| 749 | * 5 : u32 buff_addr | ||
| 750 | * Outputs: | ||
| 751 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 752 | * 2 : buff_size << 4 | 0xA | ||
| 753 | * 3 : u32 buff_addr | ||
| 754 | */ | ||
| 755 | void RegisterImmediateTask(Service::Interface* self); | ||
| 756 | |||
| 757 | /** | ||
| 758 | * BOSS::SetTaskQuery service function | ||
| 759 | * Inputs: | ||
| 760 | * 0 : Header Code[0x00360084] | ||
| 761 | * 1 : u32 unknown value | ||
| 762 | * 2 : u32 unknown value | ||
| 763 | * 3 : MappedBufferDesc1(permission = R) | ||
| 764 | * 4 : u32 buff1_addr | ||
| 765 | * 5 : MappedBufferDesc2(permission = R) | ||
| 766 | * 6 : u32 buff2_addr | ||
| 767 | * Outputs: | ||
| 768 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 769 | * 2 : buff1_size << 4 | 0xA | ||
| 770 | * 3 : u32 buff1_addr | ||
| 771 | * 4 : buff2_size << 4 | 0xA | ||
| 772 | * 5 : u32 buff2_addr | ||
| 773 | */ | ||
| 774 | void SetTaskQuery(Service::Interface* self); | ||
| 775 | |||
| 776 | /** | ||
| 777 | * BOSS::GetTaskQuery service function | ||
| 778 | * Inputs: | ||
| 779 | * 0 : Header Code[0x00370084] | ||
| 780 | * 1 : u32 unknown value | ||
| 781 | * 2 : u32 unknown value | ||
| 782 | * 3 : MappedBufferDesc1(permission = R) | ||
| 783 | * 4 : u32 buff1_addr | ||
| 784 | * 5 : MappedBufferDesc2(permission = W) | ||
| 785 | * 6 : u32 buff2_addr | ||
| 786 | * Outputs: | ||
| 787 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 788 | * 2 : buff1_size << 4 | 0xA | ||
| 789 | * 3 : u32 buff1_addr | ||
| 790 | * 4 : buff2_size << 4 | 0xC | ||
| 791 | * 5 : u32 buff2_addr | ||
| 792 | */ | ||
| 793 | void GetTaskQuery(Service::Interface* self); | ||
| 794 | |||
| 795 | /// Initialize BOSS service(s) | ||
| 796 | void Init(); | ||
| 797 | |||
| 798 | /// Shutdown BOSS service(s) | ||
| 799 | void Shutdown(); | ||
| 800 | |||
| 801 | } // namespace BOSS | ||
| 802 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp deleted file mode 100644 index 3990d0d6e..000000000 --- a/src/core/hle/service/boss/boss_p.cpp +++ /dev/null | |||
| @@ -1,86 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/boss/boss.h" | ||
| 6 | #include "core/hle/service/boss/boss_p.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace BOSS { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // boss:u shared commands | ||
| 13 | {0x00010082, InitializeSession, "InitializeSession"}, | ||
| 14 | {0x00020100, RegisterStorage, "RegisterStorage"}, | ||
| 15 | {0x00030000, UnregisterStorage, "UnregisterStorage"}, | ||
| 16 | {0x00040000, GetStorageInfo, "GetStorageInfo"}, | ||
| 17 | {0x00050042, RegisterPrivateRootCa, "RegisterPrivateRootCa"}, | ||
| 18 | {0x00060084, RegisterPrivateClientCert, "RegisterPrivateClientCert"}, | ||
| 19 | {0x00070000, GetNewArrivalFlag, "GetNewArrivalFlag"}, | ||
| 20 | {0x00080002, RegisterNewArrivalEvent, "RegisterNewArrivalEvent"}, | ||
| 21 | {0x00090040, SetOptoutFlag, "SetOptoutFlag"}, | ||
| 22 | {0x000A0000, GetOptoutFlag, "GetOptoutFlag"}, | ||
| 23 | {0x000B00C2, RegisterTask, "RegisterTask"}, | ||
| 24 | {0x000C0082, UnregisterTask, "UnregisterTask"}, | ||
| 25 | {0x000D0082, ReconfigureTask, "ReconfigureTask"}, | ||
| 26 | {0x000E0000, GetTaskIdList, "GetTaskIdList"}, | ||
| 27 | {0x000F0042, GetStepIdList, "GetStepIdList"}, | ||
| 28 | {0x00100102, GetNsDataIdList, "GetNsDataIdList"}, | ||
| 29 | {0x00110102, GetOwnNsDataIdList, "GetOwnNsDataIdList"}, | ||
| 30 | {0x00120102, GetNewDataNsDataIdList, "GetNewDataNsDataIdList"}, | ||
| 31 | {0x00130102, GetOwnNewDataNsDataIdList, "GetOwnNewDataNsDataIdList"}, | ||
| 32 | {0x00140082, SendProperty, "SendProperty"}, | ||
| 33 | {0x00150042, SendPropertyHandle, "SendPropertyHandle"}, | ||
| 34 | {0x00160082, ReceiveProperty, "ReceiveProperty"}, | ||
| 35 | {0x00170082, UpdateTaskInterval, "UpdateTaskInterval"}, | ||
| 36 | {0x00180082, UpdateTaskCount, "UpdateTaskCount"}, | ||
| 37 | {0x00190042, GetTaskInterval, "GetTaskInterval"}, | ||
| 38 | {0x001A0042, GetTaskCount, "GetTaskCount"}, | ||
| 39 | {0x001B0042, GetTaskServiceStatus, "GetTaskServiceStatus"}, | ||
| 40 | {0x001C0042, StartTask, "StartTask"}, | ||
| 41 | {0x001D0042, StartTaskImmediate, "StartTaskImmediate"}, | ||
| 42 | {0x001E0042, CancelTask, "CancelTask"}, | ||
| 43 | {0x001F0000, GetTaskFinishHandle, "GetTaskFinishHandle"}, | ||
| 44 | {0x00200082, GetTaskState, "GetTaskState"}, | ||
| 45 | {0x00210042, GetTaskResult, "GetTaskResult"}, | ||
| 46 | {0x00220042, GetTaskCommErrorCode, "GetTaskCommErrorCode"}, | ||
| 47 | {0x002300C2, GetTaskStatus, "GetTaskStatus"}, | ||
| 48 | {0x00240082, GetTaskError, "GetTaskError"}, | ||
| 49 | {0x00250082, GetTaskInfo, "GetTaskInfo"}, | ||
| 50 | {0x00260040, DeleteNsData, "DeleteNsData"}, | ||
| 51 | {0x002700C2, GetNsDataHeaderInfo, "GetNsDataHeaderInfo"}, | ||
| 52 | {0x00280102, ReadNsData, "ReadNsData"}, | ||
| 53 | {0x00290080, SetNsDataAdditionalInfo, "SetNsDataAdditionalInfo"}, | ||
| 54 | {0x002A0040, GetNsDataAdditionalInfo, "GetNsDataAdditionalInfo"}, | ||
| 55 | {0x002B0080, SetNsDataNewFlag, "SetNsDataNewFlag"}, | ||
| 56 | {0x002C0040, GetNsDataNewFlag, "GetNsDataNewFlag"}, | ||
| 57 | {0x002D0040, GetNsDataLastUpdate, "GetNsDataLastUpdate"}, | ||
| 58 | {0x002E0040, GetErrorCode, "GetErrorCode"}, | ||
| 59 | {0x002F0140, RegisterStorageEntry, "RegisterStorageEntry"}, | ||
| 60 | {0x00300000, GetStorageEntryInfo, "GetStorageEntryInfo"}, | ||
| 61 | {0x00310100, SetStorageOption, "SetStorageOption"}, | ||
| 62 | {0x00320000, GetStorageOption, "GetStorageOption"}, | ||
| 63 | {0x00330042, StartBgImmediate, "StartBgImmediate"}, | ||
| 64 | {0x00340042, GetTaskActivePriority, "GetTaskActivePriority"}, | ||
| 65 | {0x003500C2, RegisterImmediateTask, "RegisterImmediateTask"}, | ||
| 66 | {0x00360084, SetTaskQuery, "SetTaskQuery"}, | ||
| 67 | {0x00370084, GetTaskQuery, "GetTaskQuery"}, | ||
| 68 | // boss:p | ||
| 69 | {0x04010082, nullptr, "InitializeSessionPrivileged"}, | ||
| 70 | {0x04040080, nullptr, "GetAppNewFlag"}, | ||
| 71 | {0x040D0182, nullptr, "GetNsDataIdListPrivileged"}, | ||
| 72 | {0x040E0182, nullptr, "GetNsDataIdListPrivileged1"}, | ||
| 73 | {0x04130082, nullptr, "SendPropertyPrivileged"}, | ||
| 74 | {0x041500C0, nullptr, "DeleteNsDataPrivileged"}, | ||
| 75 | {0x04160142, nullptr, "GetNsDataHeaderInfoPrivileged"}, | ||
| 76 | {0x04170182, nullptr, "ReadNsDataPrivileged"}, | ||
| 77 | {0x041A0100, nullptr, "SetNsDataNewFlagPrivileged"}, | ||
| 78 | {0x041B00C0, nullptr, "GetNsDataNewFlagPrivileged"}, | ||
| 79 | }; | ||
| 80 | |||
| 81 | BOSS_P_Interface::BOSS_P_Interface() { | ||
| 82 | Register(FunctionTable); | ||
| 83 | } | ||
| 84 | |||
| 85 | } // namespace BOSS | ||
| 86 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h deleted file mode 100644 index 32112c251..000000000 --- a/src/core/hle/service/boss/boss_p.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace BOSS { | ||
| 11 | |||
| 12 | class BOSS_P_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | BOSS_P_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "boss:P"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace BOSS | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp deleted file mode 100644 index 371d702e0..000000000 --- a/src/core/hle/service/boss/boss_u.cpp +++ /dev/null | |||
| @@ -1,74 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/boss/boss.h" | ||
| 6 | #include "core/hle/service/boss/boss_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace BOSS { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010082, InitializeSession, "InitializeSession"}, | ||
| 13 | {0x00020100, RegisterStorage, "RegisterStorage"}, | ||
| 14 | {0x00030000, UnregisterStorage, "UnregisterStorage"}, | ||
| 15 | {0x00040000, GetStorageInfo, "GetStorageInfo"}, | ||
| 16 | {0x00050042, RegisterPrivateRootCa, "RegisterPrivateRootCa"}, | ||
| 17 | {0x00060084, RegisterPrivateClientCert, "RegisterPrivateClientCert"}, | ||
| 18 | {0x00070000, GetNewArrivalFlag, "GetNewArrivalFlag"}, | ||
| 19 | {0x00080002, RegisterNewArrivalEvent, "RegisterNewArrivalEvent"}, | ||
| 20 | {0x00090040, SetOptoutFlag, "SetOptoutFlag"}, | ||
| 21 | {0x000A0000, GetOptoutFlag, "GetOptoutFlag"}, | ||
| 22 | {0x000B00C2, RegisterTask, "RegisterTask"}, | ||
| 23 | {0x000C0082, UnregisterTask, "UnregisterTask"}, | ||
| 24 | {0x000D0082, ReconfigureTask, "ReconfigureTask"}, | ||
| 25 | {0x000E0000, GetTaskIdList, "GetTaskIdList"}, | ||
| 26 | {0x000F0042, GetStepIdList, "GetStepIdList"}, | ||
| 27 | {0x00100102, GetNsDataIdList, "GetNsDataIdList"}, | ||
| 28 | {0x00110102, GetOwnNsDataIdList, "GetOwnNsDataIdList"}, | ||
| 29 | {0x00120102, GetNewDataNsDataIdList, "GetNewDataNsDataIdList"}, | ||
| 30 | {0x00130102, GetOwnNewDataNsDataIdList, "GetOwnNewDataNsDataIdList"}, | ||
| 31 | {0x00140082, SendProperty, "SendProperty"}, | ||
| 32 | {0x00150042, SendPropertyHandle, "SendPropertyHandle"}, | ||
| 33 | {0x00160082, ReceiveProperty, "ReceiveProperty"}, | ||
| 34 | {0x00170082, UpdateTaskInterval, "UpdateTaskInterval"}, | ||
| 35 | {0x00180082, UpdateTaskCount, "UpdateTaskCount"}, | ||
| 36 | {0x00190042, GetTaskInterval, "GetTaskInterval"}, | ||
| 37 | {0x001A0042, GetTaskCount, "GetTaskCount"}, | ||
| 38 | {0x001B0042, GetTaskServiceStatus, "GetTaskServiceStatus"}, | ||
| 39 | {0x001C0042, StartTask, "StartTask"}, | ||
| 40 | {0x001D0042, StartTaskImmediate, "StartTaskImmediate"}, | ||
| 41 | {0x001E0042, CancelTask, "CancelTask"}, | ||
| 42 | {0x001F0000, GetTaskFinishHandle, "GetTaskFinishHandle"}, | ||
| 43 | {0x00200082, GetTaskState, "GetTaskState"}, | ||
| 44 | {0x00210042, GetTaskResult, "GetTaskResult"}, | ||
| 45 | {0x00220042, GetTaskCommErrorCode, "GetTaskCommErrorCode"}, | ||
| 46 | {0x002300C2, GetTaskStatus, "GetTaskStatus"}, | ||
| 47 | {0x00240082, GetTaskError, "GetTaskError"}, | ||
| 48 | {0x00250082, GetTaskInfo, "GetTaskInfo"}, | ||
| 49 | {0x00260040, DeleteNsData, "DeleteNsData"}, | ||
| 50 | {0x002700C2, GetNsDataHeaderInfo, "GetNsDataHeaderInfo"}, | ||
| 51 | {0x00280102, ReadNsData, "ReadNsData"}, | ||
| 52 | {0x00290080, SetNsDataAdditionalInfo, "SetNsDataAdditionalInfo"}, | ||
| 53 | {0x002A0040, GetNsDataAdditionalInfo, "GetNsDataAdditionalInfo"}, | ||
| 54 | {0x002B0080, SetNsDataNewFlag, "SetNsDataNewFlag"}, | ||
| 55 | {0x002C0040, GetNsDataNewFlag, "GetNsDataNewFlag"}, | ||
| 56 | {0x002D0040, GetNsDataLastUpdate, "GetNsDataLastUpdate"}, | ||
| 57 | {0x002E0040, GetErrorCode, "GetErrorCode"}, | ||
| 58 | {0x002F0140, RegisterStorageEntry, "RegisterStorageEntry"}, | ||
| 59 | {0x00300000, GetStorageEntryInfo, "GetStorageEntryInfo"}, | ||
| 60 | {0x00310100, SetStorageOption, "SetStorageOption"}, | ||
| 61 | {0x00320000, GetStorageOption, "GetStorageOption"}, | ||
| 62 | {0x00330042, StartBgImmediate, "StartBgImmediate"}, | ||
| 63 | {0x00340042, GetTaskActivePriority, "GetTaskActivePriority"}, | ||
| 64 | {0x003500C2, RegisterImmediateTask, "RegisterImmediateTask"}, | ||
| 65 | {0x00360084, SetTaskQuery, "SetTaskQuery"}, | ||
| 66 | {0x00370084, GetTaskQuery, "GetTaskQuery"}, | ||
| 67 | }; | ||
| 68 | |||
| 69 | BOSS_U_Interface::BOSS_U_Interface() { | ||
| 70 | Register(FunctionTable); | ||
| 71 | } | ||
| 72 | |||
| 73 | } // namespace BOSS | ||
| 74 | } // namespace Service | ||
diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h deleted file mode 100644 index d047d8cf2..000000000 --- a/src/core/hle/service/boss/boss_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace BOSS { | ||
| 11 | |||
| 12 | class BOSS_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | BOSS_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "boss:U"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace BOSS | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp deleted file mode 100644 index 8172edae8..000000000 --- a/src/core/hle/service/cam/cam.cpp +++ /dev/null | |||
| @@ -1,1106 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include <future> | ||
| 8 | #include <memory> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/bit_set.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "core/core_timing.h" | ||
| 13 | #include "core/frontend/camera/factory.h" | ||
| 14 | #include "core/hle/ipc.h" | ||
| 15 | #include "core/hle/ipc_helpers.h" | ||
| 16 | #include "core/hle/kernel/event.h" | ||
| 17 | #include "core/hle/result.h" | ||
| 18 | #include "core/hle/service/cam/cam.h" | ||
| 19 | #include "core/hle/service/cam/cam_c.h" | ||
| 20 | #include "core/hle/service/cam/cam_q.h" | ||
| 21 | #include "core/hle/service/cam/cam_s.h" | ||
| 22 | #include "core/hle/service/cam/cam_u.h" | ||
| 23 | #include "core/hle/service/service.h" | ||
| 24 | #include "core/memory.h" | ||
| 25 | #include "core/settings.h" | ||
| 26 | |||
| 27 | namespace Service { | ||
| 28 | namespace CAM { | ||
| 29 | |||
| 30 | namespace { | ||
| 31 | |||
| 32 | struct ContextConfig { | ||
| 33 | Flip flip; | ||
| 34 | Effect effect; | ||
| 35 | OutputFormat format; | ||
| 36 | Resolution resolution; | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct CameraConfig { | ||
| 40 | std::unique_ptr<Camera::CameraInterface> impl; | ||
| 41 | std::array<ContextConfig, 2> contexts; | ||
| 42 | int current_context; | ||
| 43 | FrameRate frame_rate; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct PortConfig { | ||
| 47 | int camera_id; | ||
| 48 | |||
| 49 | bool is_active; // set when the port is activated by an Activate call. | ||
| 50 | bool is_pending_receiving; // set if SetReceiving is called when is_busy = false. When | ||
| 51 | // StartCapture is called then, this will trigger a receiving | ||
| 52 | // process and reset itself. | ||
| 53 | bool is_busy; // set when StartCapture is called and reset when StopCapture is called. | ||
| 54 | bool is_receiving; // set when there is an ongoing receiving process. | ||
| 55 | |||
| 56 | bool is_trimming; | ||
| 57 | u16 x0; // x-coordinate of starting position for trimming | ||
| 58 | u16 y0; // y-coordinate of starting position for trimming | ||
| 59 | u16 x1; // x-coordinate of ending position for trimming | ||
| 60 | u16 y1; // y-coordinate of ending position for trimming | ||
| 61 | |||
| 62 | u16 transfer_bytes; | ||
| 63 | |||
| 64 | Kernel::SharedPtr<Kernel::Event> completion_event; | ||
| 65 | Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event; | ||
| 66 | Kernel::SharedPtr<Kernel::Event> vsync_interrupt_event; | ||
| 67 | |||
| 68 | std::future<std::vector<u16>> capture_result; // will hold the received frame. | ||
| 69 | VAddr dest; // the destination address of a receiving process | ||
| 70 | u32 dest_size; // the destination size of a receiving process | ||
| 71 | |||
| 72 | void Clear() { | ||
| 73 | completion_event->Clear(); | ||
| 74 | buffer_error_interrupt_event->Clear(); | ||
| 75 | vsync_interrupt_event->Clear(); | ||
| 76 | is_receiving = false; | ||
| 77 | is_active = false; | ||
| 78 | is_pending_receiving = false; | ||
| 79 | is_busy = false; | ||
| 80 | is_trimming = false; | ||
| 81 | x0 = 0; | ||
| 82 | y0 = 0; | ||
| 83 | x1 = 0; | ||
| 84 | y1 = 0; | ||
| 85 | transfer_bytes = 256; | ||
| 86 | } | ||
| 87 | }; | ||
| 88 | |||
| 89 | // built-in resolution parameters | ||
| 90 | constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{ | ||
| 91 | {640, 480, 0, 0, 639, 479}, // VGA | ||
| 92 | {320, 240, 0, 0, 639, 479}, // QVGA | ||
| 93 | {160, 120, 0, 0, 639, 479}, // QQVGA | ||
| 94 | {352, 288, 26, 0, 613, 479}, // CIF | ||
| 95 | {176, 144, 26, 0, 613, 479}, // QCIF | ||
| 96 | {256, 192, 0, 0, 639, 479}, // DS_LCD | ||
| 97 | {512, 384, 0, 0, 639, 479}, // DS_LCDx4 | ||
| 98 | {400, 240, 0, 48, 639, 431}, // CTR_TOP_LCD | ||
| 99 | }}; | ||
| 100 | |||
| 101 | // latency in ms for each frame rate option | ||
| 102 | constexpr std::array<int, 13> LATENCY_BY_FRAME_RATE{{ | ||
| 103 | 67, // Rate_15 | ||
| 104 | 67, // Rate_15_To_5 | ||
| 105 | 67, // Rate_15_To_2 | ||
| 106 | 100, // Rate_10 | ||
| 107 | 118, // Rate_8_5 | ||
| 108 | 200, // Rate_5 | ||
| 109 | 50, // Rate_20 | ||
| 110 | 50, // Rate_20_To_5 | ||
| 111 | 33, // Rate_30 | ||
| 112 | 33, // Rate_30_To_5 | ||
| 113 | 67, // Rate_15_To_10 | ||
| 114 | 50, // Rate_20_To_10 | ||
| 115 | 33, // Rate_30_To_10 | ||
| 116 | }}; | ||
| 117 | |||
| 118 | std::array<CameraConfig, NumCameras> cameras; | ||
| 119 | std::array<PortConfig, 2> ports; | ||
| 120 | int completion_event_callback; | ||
| 121 | |||
| 122 | const ResultCode ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM, | ||
| 123 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 124 | const ResultCode ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM, | ||
| 125 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 126 | |||
| 127 | void CompletionEventCallBack(u64 port_id, int) { | ||
| 128 | PortConfig& port = ports[port_id]; | ||
| 129 | const CameraConfig& camera = cameras[port.camera_id]; | ||
| 130 | const auto buffer = port.capture_result.get(); | ||
| 131 | |||
| 132 | if (port.is_trimming) { | ||
| 133 | u32 trim_width; | ||
| 134 | u32 trim_height; | ||
| 135 | const int original_width = camera.contexts[camera.current_context].resolution.width; | ||
| 136 | const int original_height = camera.contexts[camera.current_context].resolution.height; | ||
| 137 | if (port.x1 <= port.x0 || port.y1 <= port.y0 || port.x1 > original_width || | ||
| 138 | port.y1 > original_height) { | ||
| 139 | LOG_ERROR(Service_CAM, "Invalid trimming coordinates x0=%u, y0=%u, x1=%u, y1=%u", | ||
| 140 | port.x0, port.y0, port.x1, port.y1); | ||
| 141 | trim_width = 0; | ||
| 142 | trim_height = 0; | ||
| 143 | } else { | ||
| 144 | trim_width = port.x1 - port.x0; | ||
| 145 | trim_height = port.y1 - port.y0; | ||
| 146 | } | ||
| 147 | |||
| 148 | u32 trim_size = (port.x1 - port.x0) * (port.y1 - port.y0) * 2; | ||
| 149 | if (port.dest_size != trim_size) { | ||
| 150 | LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%u)!", | ||
| 151 | port.dest_size, trim_size); | ||
| 152 | } | ||
| 153 | |||
| 154 | const u32 src_offset = port.y0 * original_width + port.x0; | ||
| 155 | const u16* src_ptr = buffer.data() + src_offset; | ||
| 156 | // Note: src_size_left is int because it can be negative if the buffer size doesn't match. | ||
| 157 | int src_size_left = static_cast<int>((buffer.size() - src_offset) * sizeof(u16)); | ||
| 158 | VAddr dest_ptr = port.dest; | ||
| 159 | // Note: dest_size_left and line_bytes are int to match the type of src_size_left. | ||
| 160 | int dest_size_left = static_cast<int>(port.dest_size); | ||
| 161 | const int line_bytes = static_cast<int>(trim_width * sizeof(u16)); | ||
| 162 | |||
| 163 | for (u32 y = 0; y < trim_height; ++y) { | ||
| 164 | int copy_length = std::min({line_bytes, dest_size_left, src_size_left}); | ||
| 165 | if (copy_length <= 0) { | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | Memory::WriteBlock(dest_ptr, src_ptr, copy_length); | ||
| 169 | dest_ptr += copy_length; | ||
| 170 | dest_size_left -= copy_length; | ||
| 171 | src_ptr += original_width; | ||
| 172 | src_size_left -= original_width * sizeof(u16); | ||
| 173 | } | ||
| 174 | } else { | ||
| 175 | std::size_t buffer_size = buffer.size() * sizeof(u16); | ||
| 176 | if (port.dest_size != buffer_size) { | ||
| 177 | LOG_ERROR(Service_CAM, "The destination size (%u) doesn't match the source (%zu)!", | ||
| 178 | port.dest_size, buffer_size); | ||
| 179 | } | ||
| 180 | Memory::WriteBlock(port.dest, buffer.data(), std::min<size_t>(port.dest_size, buffer_size)); | ||
| 181 | } | ||
| 182 | |||
| 183 | port.is_receiving = false; | ||
| 184 | port.completion_event->Signal(); | ||
| 185 | } | ||
| 186 | |||
| 187 | // Starts a receiving process on the specified port. This can only be called when is_busy = true and | ||
| 188 | // is_receiving = false. | ||
| 189 | void StartReceiving(int port_id) { | ||
| 190 | PortConfig& port = ports[port_id]; | ||
| 191 | port.is_receiving = true; | ||
| 192 | |||
| 193 | // launches a capture task asynchronously | ||
| 194 | const CameraConfig& camera = cameras[port.camera_id]; | ||
| 195 | port.capture_result = | ||
| 196 | std::async(std::launch::async, &Camera::CameraInterface::ReceiveFrame, camera.impl.get()); | ||
| 197 | |||
| 198 | // schedules a completion event according to the frame rate. The event will block on the | ||
| 199 | // capture task if it is not finished within the expected time | ||
| 200 | CoreTiming::ScheduleEvent( | ||
| 201 | msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(camera.frame_rate)]), | ||
| 202 | completion_event_callback, port_id); | ||
| 203 | } | ||
| 204 | |||
| 205 | // Cancels any ongoing receiving processes at the specified port. This is used by functions that | ||
| 206 | // stop capturing. | ||
| 207 | // TODO: what is the exact behaviour on real 3DS when stopping capture during an ongoing process? | ||
| 208 | // Will the completion event still be signaled? | ||
| 209 | void CancelReceiving(int port_id) { | ||
| 210 | if (!ports[port_id].is_receiving) | ||
| 211 | return; | ||
| 212 | LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process."); | ||
| 213 | CoreTiming::UnscheduleEvent(completion_event_callback, port_id); | ||
| 214 | ports[port_id].capture_result.wait(); | ||
| 215 | ports[port_id].is_receiving = false; | ||
| 216 | } | ||
| 217 | |||
| 218 | // Activates the specified port with the specfied camera. | ||
| 219 | static void ActivatePort(int port_id, int camera_id) { | ||
| 220 | if (ports[port_id].is_busy && ports[port_id].camera_id != camera_id) { | ||
| 221 | CancelReceiving(port_id); | ||
| 222 | cameras[ports[port_id].camera_id].impl->StopCapture(); | ||
| 223 | ports[port_id].is_busy = false; | ||
| 224 | } | ||
| 225 | ports[port_id].is_active = true; | ||
| 226 | ports[port_id].camera_id = camera_id; | ||
| 227 | } | ||
| 228 | |||
| 229 | template <int max_index> | ||
| 230 | class CommandParamBitSet : public BitSet8 { | ||
| 231 | public: | ||
| 232 | explicit CommandParamBitSet(u8 command_param) : BitSet8(command_param) {} | ||
| 233 | |||
| 234 | bool IsValid() const { | ||
| 235 | return m_val < (1 << max_index); | ||
| 236 | } | ||
| 237 | |||
| 238 | bool IsSingle() const { | ||
| 239 | return IsValid() && Count() == 1; | ||
| 240 | } | ||
| 241 | }; | ||
| 242 | |||
| 243 | using PortSet = CommandParamBitSet<2>; | ||
| 244 | using ContextSet = CommandParamBitSet<2>; | ||
| 245 | using CameraSet = CommandParamBitSet<3>; | ||
| 246 | |||
| 247 | } // namespace | ||
| 248 | |||
| 249 | void StartCapture(Service::Interface* self) { | ||
| 250 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0); | ||
| 251 | const PortSet port_select(rp.Pop<u8>()); | ||
| 252 | |||
| 253 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 254 | |||
| 255 | if (port_select.IsValid()) { | ||
| 256 | for (int i : port_select) { | ||
| 257 | if (!ports[i].is_busy) { | ||
| 258 | if (!ports[i].is_active) { | ||
| 259 | // This doesn't return an error, but seems to put the camera in an undefined | ||
| 260 | // state | ||
| 261 | LOG_ERROR(Service_CAM, "port %u hasn't been activated", i); | ||
| 262 | } else { | ||
| 263 | cameras[ports[i].camera_id].impl->StartCapture(); | ||
| 264 | ports[i].is_busy = true; | ||
| 265 | if (ports[i].is_pending_receiving) { | ||
| 266 | ports[i].is_pending_receiving = false; | ||
| 267 | StartReceiving(i); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } else { | ||
| 271 | LOG_WARNING(Service_CAM, "port %u already started", i); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | rb.Push(RESULT_SUCCESS); | ||
| 275 | } else { | ||
| 276 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 277 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 278 | } | ||
| 279 | |||
| 280 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 281 | } | ||
| 282 | |||
| 283 | void StopCapture(Service::Interface* self) { | ||
| 284 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0); | ||
| 285 | const PortSet port_select(rp.Pop<u8>()); | ||
| 286 | |||
| 287 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 288 | |||
| 289 | if (port_select.IsValid()) { | ||
| 290 | for (int i : port_select) { | ||
| 291 | if (ports[i].is_busy) { | ||
| 292 | CancelReceiving(i); | ||
| 293 | cameras[ports[i].camera_id].impl->StopCapture(); | ||
| 294 | ports[i].is_busy = false; | ||
| 295 | } else { | ||
| 296 | LOG_WARNING(Service_CAM, "port %u already stopped", i); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | rb.Push(RESULT_SUCCESS); | ||
| 300 | } else { | ||
| 301 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 302 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 303 | } | ||
| 304 | |||
| 305 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 306 | } | ||
| 307 | |||
| 308 | void IsBusy(Service::Interface* self) { | ||
| 309 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); | ||
| 310 | const PortSet port_select(rp.Pop<u8>()); | ||
| 311 | |||
| 312 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 313 | |||
| 314 | if (port_select.IsValid()) { | ||
| 315 | bool is_busy = true; | ||
| 316 | // Note: the behaviour on no or both ports selected are verified against real 3DS. | ||
| 317 | for (int i : port_select) { | ||
| 318 | is_busy &= ports[i].is_busy; | ||
| 319 | } | ||
| 320 | rb.Push(RESULT_SUCCESS); | ||
| 321 | rb.Push(is_busy); | ||
| 322 | } else { | ||
| 323 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 324 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 325 | rb.Skip(1, false); | ||
| 326 | } | ||
| 327 | |||
| 328 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 329 | } | ||
| 330 | |||
| 331 | void ClearBuffer(Service::Interface* self) { | ||
| 332 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0); | ||
| 333 | const PortSet port_select(rp.Pop<u8>()); | ||
| 334 | |||
| 335 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 336 | rb.Push(RESULT_SUCCESS); | ||
| 337 | |||
| 338 | LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); | ||
| 339 | } | ||
| 340 | |||
| 341 | void GetVsyncInterruptEvent(Service::Interface* self) { | ||
| 342 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0); | ||
| 343 | const PortSet port_select(rp.Pop<u8>()); | ||
| 344 | |||
| 345 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 346 | if (port_select.IsSingle()) { | ||
| 347 | int port = *port_select.begin(); | ||
| 348 | rb.Push(RESULT_SUCCESS); | ||
| 349 | rb.PushCopyHandles( | ||
| 350 | Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).Unwrap()); | ||
| 351 | } else { | ||
| 352 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 353 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 354 | rb.PushCopyHandles(0); | ||
| 355 | } | ||
| 356 | |||
| 357 | LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); | ||
| 358 | } | ||
| 359 | |||
| 360 | void GetBufferErrorInterruptEvent(Service::Interface* self) { | ||
| 361 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0); | ||
| 362 | const PortSet port_select(rp.Pop<u8>()); | ||
| 363 | |||
| 364 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 365 | if (port_select.IsSingle()) { | ||
| 366 | int port = *port_select.begin(); | ||
| 367 | rb.Push(RESULT_SUCCESS); | ||
| 368 | rb.PushCopyHandles( | ||
| 369 | Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).Unwrap()); | ||
| 370 | } else { | ||
| 371 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 372 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 373 | rb.PushCopyHandles(0); | ||
| 374 | } | ||
| 375 | |||
| 376 | LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); | ||
| 377 | } | ||
| 378 | |||
| 379 | void SetReceiving(Service::Interface* self) { | ||
| 380 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2); | ||
| 381 | const VAddr dest = rp.Pop<u32>(); | ||
| 382 | const PortSet port_select(rp.Pop<u8>()); | ||
| 383 | const u32 image_size = rp.Pop<u32>(); | ||
| 384 | const u16 trans_unit = rp.Pop<u16>(); | ||
| 385 | rp.PopHandle(); // Handle to destination process. not used | ||
| 386 | |||
| 387 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 388 | if (port_select.IsSingle()) { | ||
| 389 | int port_id = *port_select.begin(); | ||
| 390 | PortConfig& port = ports[port_id]; | ||
| 391 | CancelReceiving(port_id); | ||
| 392 | port.completion_event->Clear(); | ||
| 393 | port.dest = dest; | ||
| 394 | port.dest_size = image_size; | ||
| 395 | |||
| 396 | if (port.is_busy) { | ||
| 397 | StartReceiving(port_id); | ||
| 398 | } else { | ||
| 399 | port.is_pending_receiving = true; | ||
| 400 | } | ||
| 401 | |||
| 402 | rb.Push(RESULT_SUCCESS); | ||
| 403 | rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).Unwrap()); | ||
| 404 | } else { | ||
| 405 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 406 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 407 | rb.PushCopyHandles(0); | ||
| 408 | } | ||
| 409 | |||
| 410 | LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest, | ||
| 411 | port_select.m_val, image_size, trans_unit); | ||
| 412 | } | ||
| 413 | |||
| 414 | void IsFinishedReceiving(Service::Interface* self) { | ||
| 415 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0); | ||
| 416 | const PortSet port_select(rp.Pop<u8>()); | ||
| 417 | |||
| 418 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 419 | if (port_select.IsSingle()) { | ||
| 420 | int port = *port_select.begin(); | ||
| 421 | bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving; | ||
| 422 | rb.Push(RESULT_SUCCESS); | ||
| 423 | rb.Push(!is_busy); | ||
| 424 | } else { | ||
| 425 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 426 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 427 | rb.Skip(1, false); | ||
| 428 | } | ||
| 429 | |||
| 430 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 431 | } | ||
| 432 | |||
| 433 | void SetTransferLines(Service::Interface* self) { | ||
| 434 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0); | ||
| 435 | const PortSet port_select(rp.Pop<u8>()); | ||
| 436 | const u16 transfer_lines = rp.Pop<u16>(); | ||
| 437 | const u16 width = rp.Pop<u16>(); | ||
| 438 | const u16 height = rp.Pop<u16>(); | ||
| 439 | |||
| 440 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 441 | if (port_select.IsValid()) { | ||
| 442 | for (int i : port_select) { | ||
| 443 | ports[i].transfer_bytes = transfer_lines * width * 2; | ||
| 444 | } | ||
| 445 | rb.Push(RESULT_SUCCESS); | ||
| 446 | } else { | ||
| 447 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 448 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 449 | } | ||
| 450 | |||
| 451 | LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u", | ||
| 452 | port_select.m_val, transfer_lines, width, height); | ||
| 453 | } | ||
| 454 | |||
| 455 | void GetMaxLines(Service::Interface* self) { | ||
| 456 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0); | ||
| 457 | const u16 width = rp.Pop<u16>(); | ||
| 458 | const u16 height = rp.Pop<u16>(); | ||
| 459 | |||
| 460 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 461 | |||
| 462 | // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 | ||
| 463 | constexpr u32 MIN_TRANSFER_UNIT = 256; | ||
| 464 | constexpr u32 MAX_BUFFER_SIZE = 2560; | ||
| 465 | if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { | ||
| 466 | rb.Push(ERROR_OUT_OF_RANGE); | ||
| 467 | rb.Skip(1, false); | ||
| 468 | } else { | ||
| 469 | u32 lines = MAX_BUFFER_SIZE / width; | ||
| 470 | if (lines > height) { | ||
| 471 | lines = height; | ||
| 472 | } | ||
| 473 | ResultCode result = RESULT_SUCCESS; | ||
| 474 | while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) { | ||
| 475 | --lines; | ||
| 476 | if (lines == 0) { | ||
| 477 | result = ERROR_OUT_OF_RANGE; | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | rb.Push(result); | ||
| 482 | rb.Push(lines); | ||
| 483 | } | ||
| 484 | |||
| 485 | LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); | ||
| 486 | } | ||
| 487 | |||
| 488 | void SetTransferBytes(Service::Interface* self) { | ||
| 489 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0); | ||
| 490 | const PortSet port_select(rp.Pop<u8>()); | ||
| 491 | const u16 transfer_bytes = rp.Pop<u16>(); | ||
| 492 | const u16 width = rp.Pop<u16>(); | ||
| 493 | const u16 height = rp.Pop<u16>(); | ||
| 494 | |||
| 495 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 496 | if (port_select.IsValid()) { | ||
| 497 | for (int i : port_select) { | ||
| 498 | ports[i].transfer_bytes = transfer_bytes; | ||
| 499 | } | ||
| 500 | rb.Push(RESULT_SUCCESS); | ||
| 501 | } else { | ||
| 502 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 503 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 504 | } | ||
| 505 | |||
| 506 | LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u", | ||
| 507 | port_select.m_val, transfer_bytes, width, height); | ||
| 508 | } | ||
| 509 | |||
| 510 | void GetTransferBytes(Service::Interface* self) { | ||
| 511 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0); | ||
| 512 | const PortSet port_select(rp.Pop<u8>()); | ||
| 513 | |||
| 514 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 515 | if (port_select.IsSingle()) { | ||
| 516 | int port = *port_select.begin(); | ||
| 517 | rb.Push(RESULT_SUCCESS); | ||
| 518 | rb.Push(ports[port].transfer_bytes); | ||
| 519 | } else { | ||
| 520 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 521 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 522 | rb.Skip(1, false); | ||
| 523 | } | ||
| 524 | |||
| 525 | LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val); | ||
| 526 | } | ||
| 527 | |||
| 528 | void GetMaxBytes(Service::Interface* self) { | ||
| 529 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0); | ||
| 530 | const u16 width = rp.Pop<u16>(); | ||
| 531 | const u16 height = rp.Pop<u16>(); | ||
| 532 | |||
| 533 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 534 | |||
| 535 | // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 | ||
| 536 | constexpr u32 MIN_TRANSFER_UNIT = 256; | ||
| 537 | constexpr u32 MAX_BUFFER_SIZE = 2560; | ||
| 538 | if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { | ||
| 539 | rb.Push(ERROR_OUT_OF_RANGE); | ||
| 540 | rb.Skip(1, false); | ||
| 541 | } else { | ||
| 542 | u32 bytes = MAX_BUFFER_SIZE; | ||
| 543 | |||
| 544 | while (width * height * 2 % bytes != 0) { | ||
| 545 | bytes -= MIN_TRANSFER_UNIT; | ||
| 546 | } | ||
| 547 | |||
| 548 | rb.Push(RESULT_SUCCESS); | ||
| 549 | rb.Push(bytes); | ||
| 550 | } | ||
| 551 | |||
| 552 | LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); | ||
| 553 | } | ||
| 554 | |||
| 555 | void SetTrimming(Service::Interface* self) { | ||
| 556 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0); | ||
| 557 | const PortSet port_select(rp.Pop<u8>()); | ||
| 558 | const bool trim = rp.Pop<bool>(); | ||
| 559 | |||
| 560 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 561 | if (port_select.IsValid()) { | ||
| 562 | for (int i : port_select) { | ||
| 563 | ports[i].is_trimming = trim; | ||
| 564 | } | ||
| 565 | rb.Push(RESULT_SUCCESS); | ||
| 566 | } else { | ||
| 567 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 568 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 569 | } | ||
| 570 | |||
| 571 | LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim); | ||
| 572 | } | ||
| 573 | |||
| 574 | void IsTrimming(Service::Interface* self) { | ||
| 575 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0); | ||
| 576 | const PortSet port_select(rp.Pop<u8>()); | ||
| 577 | |||
| 578 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 579 | if (port_select.IsSingle()) { | ||
| 580 | int port = *port_select.begin(); | ||
| 581 | rb.Push(RESULT_SUCCESS); | ||
| 582 | rb.Push(ports[port].is_trimming); | ||
| 583 | } else { | ||
| 584 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 585 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 586 | rb.Skip(1, false); | ||
| 587 | } | ||
| 588 | |||
| 589 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 590 | } | ||
| 591 | |||
| 592 | void SetTrimmingParams(Service::Interface* self) { | ||
| 593 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0); | ||
| 594 | const PortSet port_select(rp.Pop<u8>()); | ||
| 595 | const u16 x0 = rp.Pop<u16>(); | ||
| 596 | const u16 y0 = rp.Pop<u16>(); | ||
| 597 | const u16 x1 = rp.Pop<u16>(); | ||
| 598 | const u16 y1 = rp.Pop<u16>(); | ||
| 599 | |||
| 600 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 601 | if (port_select.IsValid()) { | ||
| 602 | for (int i : port_select) { | ||
| 603 | ports[i].x0 = x0; | ||
| 604 | ports[i].y0 = y0; | ||
| 605 | ports[i].x1 = x1; | ||
| 606 | ports[i].y1 = y1; | ||
| 607 | } | ||
| 608 | rb.Push(RESULT_SUCCESS); | ||
| 609 | } else { | ||
| 610 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 611 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 612 | } | ||
| 613 | |||
| 614 | LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val, | ||
| 615 | x0, y0, x1, y1); | ||
| 616 | } | ||
| 617 | |||
| 618 | void GetTrimmingParams(Service::Interface* self) { | ||
| 619 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0); | ||
| 620 | const PortSet port_select(rp.Pop<u8>()); | ||
| 621 | |||
| 622 | IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); | ||
| 623 | if (port_select.IsSingle()) { | ||
| 624 | int port = *port_select.begin(); | ||
| 625 | rb.Push(RESULT_SUCCESS); | ||
| 626 | rb.Push(ports[port].x0); | ||
| 627 | rb.Push(ports[port].y0); | ||
| 628 | rb.Push(ports[port].x1); | ||
| 629 | rb.Push(ports[port].y1); | ||
| 630 | } else { | ||
| 631 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 632 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 633 | rb.Skip(4, false); | ||
| 634 | } | ||
| 635 | |||
| 636 | LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); | ||
| 637 | } | ||
| 638 | |||
| 639 | void SetTrimmingParamsCenter(Service::Interface* self) { | ||
| 640 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0); | ||
| 641 | const PortSet port_select(rp.Pop<u8>()); | ||
| 642 | const u16 trim_w = rp.Pop<u16>(); | ||
| 643 | const u16 trim_h = rp.Pop<u16>(); | ||
| 644 | const u16 cam_w = rp.Pop<u16>(); | ||
| 645 | const u16 cam_h = rp.Pop<u16>(); | ||
| 646 | |||
| 647 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 648 | if (port_select.IsValid()) { | ||
| 649 | for (int i : port_select) { | ||
| 650 | ports[i].x0 = (cam_w - trim_w) / 2; | ||
| 651 | ports[i].y0 = (cam_h - trim_h) / 2; | ||
| 652 | ports[i].x1 = ports[i].x0 + trim_w; | ||
| 653 | ports[i].y1 = ports[i].y0 + trim_h; | ||
| 654 | } | ||
| 655 | rb.Push(RESULT_SUCCESS); | ||
| 656 | } else { | ||
| 657 | LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); | ||
| 658 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 659 | } | ||
| 660 | |||
| 661 | LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u", | ||
| 662 | port_select.m_val, trim_w, trim_h, cam_w, cam_h); | ||
| 663 | } | ||
| 664 | |||
| 665 | void Activate(Service::Interface* self) { | ||
| 666 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0); | ||
| 667 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 668 | |||
| 669 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 670 | if (camera_select.IsValid()) { | ||
| 671 | if (camera_select.m_val == 0) { // deactive all | ||
| 672 | for (int i = 0; i < 2; ++i) { | ||
| 673 | if (ports[i].is_busy) { | ||
| 674 | CancelReceiving(i); | ||
| 675 | cameras[ports[i].camera_id].impl->StopCapture(); | ||
| 676 | ports[i].is_busy = false; | ||
| 677 | } | ||
| 678 | ports[i].is_active = false; | ||
| 679 | } | ||
| 680 | rb.Push(RESULT_SUCCESS); | ||
| 681 | } else if (camera_select[0] && camera_select[1]) { | ||
| 682 | LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated"); | ||
| 683 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 684 | } else { | ||
| 685 | if (camera_select[0]) { | ||
| 686 | ActivatePort(0, 0); | ||
| 687 | } else if (camera_select[1]) { | ||
| 688 | ActivatePort(0, 1); | ||
| 689 | } | ||
| 690 | |||
| 691 | if (camera_select[2]) { | ||
| 692 | ActivatePort(1, 2); | ||
| 693 | } | ||
| 694 | rb.Push(RESULT_SUCCESS); | ||
| 695 | } | ||
| 696 | } else { | ||
| 697 | LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); | ||
| 698 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 699 | } | ||
| 700 | |||
| 701 | LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val); | ||
| 702 | } | ||
| 703 | |||
| 704 | void SwitchContext(Service::Interface* self) { | ||
| 705 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0); | ||
| 706 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 707 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 708 | |||
| 709 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 710 | if (camera_select.IsValid() && context_select.IsSingle()) { | ||
| 711 | int context = *context_select.begin(); | ||
| 712 | for (int camera : camera_select) { | ||
| 713 | cameras[camera].current_context = context; | ||
| 714 | const ContextConfig& context_config = cameras[camera].contexts[context]; | ||
| 715 | cameras[camera].impl->SetFlip(context_config.flip); | ||
| 716 | cameras[camera].impl->SetEffect(context_config.effect); | ||
| 717 | cameras[camera].impl->SetFormat(context_config.format); | ||
| 718 | cameras[camera].impl->SetResolution(context_config.resolution); | ||
| 719 | } | ||
| 720 | rb.Push(RESULT_SUCCESS); | ||
| 721 | } else { | ||
| 722 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 723 | context_select.m_val); | ||
| 724 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 725 | } | ||
| 726 | |||
| 727 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 728 | context_select.m_val); | ||
| 729 | } | ||
| 730 | |||
| 731 | void FlipImage(Service::Interface* self) { | ||
| 732 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0); | ||
| 733 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 734 | const Flip flip = static_cast<Flip>(rp.Pop<u8>()); | ||
| 735 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 736 | |||
| 737 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 738 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 739 | for (int camera : camera_select) { | ||
| 740 | for (int context : context_select) { | ||
| 741 | cameras[camera].contexts[context].flip = flip; | ||
| 742 | if (cameras[camera].current_context == context) { | ||
| 743 | cameras[camera].impl->SetFlip(flip); | ||
| 744 | } | ||
| 745 | } | ||
| 746 | } | ||
| 747 | rb.Push(RESULT_SUCCESS); | ||
| 748 | } else { | ||
| 749 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 750 | context_select.m_val); | ||
| 751 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 752 | } | ||
| 753 | |||
| 754 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u", | ||
| 755 | camera_select.m_val, static_cast<int>(flip), context_select.m_val); | ||
| 756 | } | ||
| 757 | |||
| 758 | void SetDetailSize(Service::Interface* self) { | ||
| 759 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0); | ||
| 760 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 761 | Resolution resolution; | ||
| 762 | resolution.width = rp.Pop<u16>(); | ||
| 763 | resolution.height = rp.Pop<u16>(); | ||
| 764 | resolution.crop_x0 = rp.Pop<u16>(); | ||
| 765 | resolution.crop_y0 = rp.Pop<u16>(); | ||
| 766 | resolution.crop_x1 = rp.Pop<u16>(); | ||
| 767 | resolution.crop_y1 = rp.Pop<u16>(); | ||
| 768 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 769 | |||
| 770 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 771 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 772 | for (int camera : camera_select) { | ||
| 773 | for (int context : context_select) { | ||
| 774 | cameras[camera].contexts[context].resolution = resolution; | ||
| 775 | if (cameras[camera].current_context == context) { | ||
| 776 | cameras[camera].impl->SetResolution(resolution); | ||
| 777 | } | ||
| 778 | } | ||
| 779 | } | ||
| 780 | rb.Push(RESULT_SUCCESS); | ||
| 781 | } else { | ||
| 782 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 783 | context_select.m_val); | ||
| 784 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 785 | } | ||
| 786 | |||
| 787 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, " | ||
| 788 | "crop_x1=%u, crop_y1=%u, context_select=%u", | ||
| 789 | camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0, | ||
| 790 | resolution.crop_y0, resolution.crop_x1, resolution.crop_y1, context_select.m_val); | ||
| 791 | } | ||
| 792 | |||
| 793 | void SetSize(Service::Interface* self) { | ||
| 794 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0); | ||
| 795 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 796 | const u8 size = rp.Pop<u8>(); | ||
| 797 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 798 | |||
| 799 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 800 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 801 | for (int camera : camera_select) { | ||
| 802 | for (int context : context_select) { | ||
| 803 | cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size]; | ||
| 804 | if (cameras[camera].current_context == context) { | ||
| 805 | cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | } | ||
| 809 | rb.Push(RESULT_SUCCESS); | ||
| 810 | } else { | ||
| 811 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 812 | context_select.m_val); | ||
| 813 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 814 | } | ||
| 815 | |||
| 816 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u", | ||
| 817 | camera_select.m_val, size, context_select.m_val); | ||
| 818 | } | ||
| 819 | |||
| 820 | void SetFrameRate(Service::Interface* self) { | ||
| 821 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0); | ||
| 822 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 823 | const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>()); | ||
| 824 | |||
| 825 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 826 | if (camera_select.IsValid()) { | ||
| 827 | for (int camera : camera_select) { | ||
| 828 | cameras[camera].frame_rate = frame_rate; | ||
| 829 | // TODO(wwylele): consider hinting the actual camera with the expected frame rate | ||
| 830 | } | ||
| 831 | rb.Push(RESULT_SUCCESS); | ||
| 832 | } else { | ||
| 833 | LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); | ||
| 834 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 835 | } | ||
| 836 | |||
| 837 | LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d", | ||
| 838 | camera_select.m_val, static_cast<int>(frame_rate)); | ||
| 839 | } | ||
| 840 | |||
| 841 | void SetEffect(Service::Interface* self) { | ||
| 842 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0); | ||
| 843 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 844 | const Effect effect = static_cast<Effect>(rp.Pop<u8>()); | ||
| 845 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 846 | |||
| 847 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 848 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 849 | for (int camera : camera_select) { | ||
| 850 | for (int context : context_select) { | ||
| 851 | cameras[camera].contexts[context].effect = effect; | ||
| 852 | if (cameras[camera].current_context == context) { | ||
| 853 | cameras[camera].impl->SetEffect(effect); | ||
| 854 | } | ||
| 855 | } | ||
| 856 | } | ||
| 857 | rb.Push(RESULT_SUCCESS); | ||
| 858 | } else { | ||
| 859 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 860 | context_select.m_val); | ||
| 861 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 862 | } | ||
| 863 | |||
| 864 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u", | ||
| 865 | camera_select.m_val, static_cast<int>(effect), context_select.m_val); | ||
| 866 | } | ||
| 867 | |||
| 868 | void SetOutputFormat(Service::Interface* self) { | ||
| 869 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0); | ||
| 870 | const CameraSet camera_select(rp.Pop<u8>()); | ||
| 871 | const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>()); | ||
| 872 | const ContextSet context_select(rp.Pop<u8>()); | ||
| 873 | |||
| 874 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 875 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 876 | for (int camera : camera_select) { | ||
| 877 | for (int context : context_select) { | ||
| 878 | cameras[camera].contexts[context].format = format; | ||
| 879 | if (cameras[camera].current_context == context) { | ||
| 880 | cameras[camera].impl->SetFormat(format); | ||
| 881 | } | ||
| 882 | } | ||
| 883 | } | ||
| 884 | rb.Push(RESULT_SUCCESS); | ||
| 885 | } else { | ||
| 886 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, | ||
| 887 | context_select.m_val); | ||
| 888 | rb.Push(ERROR_INVALID_ENUM_VALUE); | ||
| 889 | } | ||
| 890 | |||
| 891 | LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u", | ||
| 892 | camera_select.m_val, static_cast<int>(format), context_select.m_val); | ||
| 893 | } | ||
| 894 | |||
| 895 | void SynchronizeVsyncTiming(Service::Interface* self) { | ||
| 896 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0); | ||
| 897 | const u8 camera_select1 = rp.Pop<u8>(); | ||
| 898 | const u8 camera_select2 = rp.Pop<u8>(); | ||
| 899 | |||
| 900 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 901 | rb.Push(RESULT_SUCCESS); | ||
| 902 | |||
| 903 | LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u", | ||
| 904 | camera_select1, camera_select2); | ||
| 905 | } | ||
| 906 | |||
| 907 | void GetStereoCameraCalibrationData(Service::Interface* self) { | ||
| 908 | IPC::RequestBuilder rb = | ||
| 909 | IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0); | ||
| 910 | |||
| 911 | // Default values taken from yuriks' 3DS. Valid data is required here or games using the | ||
| 912 | // calibration get stuck in an infinite CPU loop. | ||
| 913 | StereoCameraCalibrationData data = {}; | ||
| 914 | data.isValidRotationXY = 0; | ||
| 915 | data.scale = 1.001776f; | ||
| 916 | data.rotationZ = 0.008322907f; | ||
| 917 | data.translationX = -87.70484f; | ||
| 918 | data.translationY = -7.640977f; | ||
| 919 | data.rotationX = 0.0f; | ||
| 920 | data.rotationY = 0.0f; | ||
| 921 | data.angleOfViewRight = 64.66875f; | ||
| 922 | data.angleOfViewLeft = 64.76067f; | ||
| 923 | data.distanceToChart = 250.0f; | ||
| 924 | data.distanceCameras = 35.0f; | ||
| 925 | data.imageWidth = 640; | ||
| 926 | data.imageHeight = 480; | ||
| 927 | |||
| 928 | rb.Push(RESULT_SUCCESS); | ||
| 929 | rb.PushRaw(data); | ||
| 930 | |||
| 931 | LOG_TRACE(Service_CAM, "called"); | ||
| 932 | } | ||
| 933 | |||
| 934 | void SetPackageParameterWithoutContext(Service::Interface* self) { | ||
| 935 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0); | ||
| 936 | |||
| 937 | PackageParameterWithoutContext package; | ||
| 938 | rp.PopRaw(package); | ||
| 939 | |||
| 940 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 941 | rb.Push(RESULT_SUCCESS); | ||
| 942 | |||
| 943 | LOG_WARNING(Service_CAM, "(STUBBED) called"); | ||
| 944 | } | ||
| 945 | |||
| 946 | template <typename PackageParameterType> | ||
| 947 | static ResultCode SetPackageParameter(const PackageParameterType& package) { | ||
| 948 | const CameraSet camera_select(package.camera_select); | ||
| 949 | const ContextSet context_select(package.context_select); | ||
| 950 | |||
| 951 | if (camera_select.IsValid() && context_select.IsValid()) { | ||
| 952 | for (int camera_id : camera_select) { | ||
| 953 | CameraConfig& camera = cameras[camera_id]; | ||
| 954 | for (int context_id : context_select) { | ||
| 955 | ContextConfig& context = camera.contexts[context_id]; | ||
| 956 | context.effect = package.effect; | ||
| 957 | context.flip = package.flip; | ||
| 958 | context.resolution = package.GetResolution(); | ||
| 959 | if (context_id == camera.current_context) { | ||
| 960 | camera.impl->SetEffect(context.effect); | ||
| 961 | camera.impl->SetFlip(context.flip); | ||
| 962 | camera.impl->SetResolution(context.resolution); | ||
| 963 | } | ||
| 964 | } | ||
| 965 | } | ||
| 966 | return RESULT_SUCCESS; | ||
| 967 | } else { | ||
| 968 | LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select, | ||
| 969 | package.context_select); | ||
| 970 | return ERROR_INVALID_ENUM_VALUE; | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | Resolution PackageParameterWithContext::GetResolution() const { | ||
| 975 | return PRESET_RESOLUTION[static_cast<int>(size)]; | ||
| 976 | } | ||
| 977 | |||
| 978 | void SetPackageParameterWithContext(Service::Interface* self) { | ||
| 979 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0); | ||
| 980 | |||
| 981 | PackageParameterWithContext package; | ||
| 982 | rp.PopRaw(package); | ||
| 983 | |||
| 984 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 985 | ResultCode result = SetPackageParameter(package); | ||
| 986 | rb.Push(result); | ||
| 987 | |||
| 988 | LOG_DEBUG(Service_CAM, "called"); | ||
| 989 | } | ||
| 990 | |||
| 991 | void SetPackageParameterWithContextDetail(Service::Interface* self) { | ||
| 992 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0); | ||
| 993 | |||
| 994 | PackageParameterWithContextDetail package; | ||
| 995 | rp.PopRaw(package); | ||
| 996 | |||
| 997 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 998 | ResultCode result = SetPackageParameter(package); | ||
| 999 | rb.Push(result); | ||
| 1000 | |||
| 1001 | LOG_DEBUG(Service_CAM, "called"); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | void GetSuitableY2rStandardCoefficient(Service::Interface* self) { | ||
| 1005 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0); | ||
| 1006 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 1007 | rb.Push(RESULT_SUCCESS); | ||
| 1008 | rb.Push<u32>(0); | ||
| 1009 | |||
| 1010 | LOG_WARNING(Service_CAM, "(STUBBED) called"); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | void PlayShutterSound(Service::Interface* self) { | ||
| 1014 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0); | ||
| 1015 | u8 sound_id = rp.Pop<u8>(); | ||
| 1016 | |||
| 1017 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 1018 | rb.Push(RESULT_SUCCESS); | ||
| 1019 | |||
| 1020 | LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | void DriverInitialize(Service::Interface* self) { | ||
| 1024 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0); | ||
| 1025 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 1026 | |||
| 1027 | for (int camera_id = 0; camera_id < NumCameras; ++camera_id) { | ||
| 1028 | CameraConfig& camera = cameras[camera_id]; | ||
| 1029 | camera.current_context = 0; | ||
| 1030 | for (int context_id = 0; context_id < 2; ++context_id) { | ||
| 1031 | // Note: the following default values are verified against real 3DS | ||
| 1032 | ContextConfig& context = camera.contexts[context_id]; | ||
| 1033 | context.flip = camera_id == 1 ? Flip::Horizontal : Flip::None; | ||
| 1034 | context.effect = Effect::None; | ||
| 1035 | context.format = OutputFormat::YUV422; | ||
| 1036 | context.resolution = | ||
| 1037 | context_id == 0 ? PRESET_RESOLUTION[5 /*DS_LCD*/] : PRESET_RESOLUTION[0 /*VGA*/]; | ||
| 1038 | } | ||
| 1039 | camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id], | ||
| 1040 | Settings::values.camera_config[camera_id]); | ||
| 1041 | camera.impl->SetFlip(camera.contexts[0].flip); | ||
| 1042 | camera.impl->SetEffect(camera.contexts[0].effect); | ||
| 1043 | camera.impl->SetFormat(camera.contexts[0].format); | ||
| 1044 | camera.impl->SetResolution(camera.contexts[0].resolution); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | for (PortConfig& port : ports) { | ||
| 1048 | port.Clear(); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | rb.Push(RESULT_SUCCESS); | ||
| 1052 | |||
| 1053 | LOG_DEBUG(Service_CAM, "called"); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | void DriverFinalize(Service::Interface* self) { | ||
| 1057 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0); | ||
| 1058 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 1059 | |||
| 1060 | CancelReceiving(0); | ||
| 1061 | CancelReceiving(1); | ||
| 1062 | |||
| 1063 | for (CameraConfig& camera : cameras) { | ||
| 1064 | camera.impl = nullptr; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | rb.Push(RESULT_SUCCESS); | ||
| 1068 | |||
| 1069 | LOG_DEBUG(Service_CAM, "called"); | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | void Init() { | ||
| 1073 | using namespace Kernel; | ||
| 1074 | |||
| 1075 | AddService(new CAM_C_Interface); | ||
| 1076 | AddService(new CAM_Q_Interface); | ||
| 1077 | AddService(new CAM_S_Interface); | ||
| 1078 | AddService(new CAM_U_Interface); | ||
| 1079 | |||
| 1080 | for (PortConfig& port : ports) { | ||
| 1081 | port.completion_event = Event::Create(ResetType::Sticky, "CAM_U::completion_event"); | ||
| 1082 | port.buffer_error_interrupt_event = | ||
| 1083 | Event::Create(ResetType::OneShot, "CAM_U::buffer_error_interrupt_event"); | ||
| 1084 | port.vsync_interrupt_event = | ||
| 1085 | Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_event"); | ||
| 1086 | } | ||
| 1087 | completion_event_callback = | ||
| 1088 | CoreTiming::RegisterEvent("CAM_U::CompletionEventCallBack", CompletionEventCallBack); | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | void Shutdown() { | ||
| 1092 | CancelReceiving(0); | ||
| 1093 | CancelReceiving(1); | ||
| 1094 | for (PortConfig& port : ports) { | ||
| 1095 | port.completion_event = nullptr; | ||
| 1096 | port.buffer_error_interrupt_event = nullptr; | ||
| 1097 | port.vsync_interrupt_event = nullptr; | ||
| 1098 | } | ||
| 1099 | for (CameraConfig& camera : cameras) { | ||
| 1100 | camera.impl = nullptr; | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | } // namespace CAM | ||
| 1105 | |||
| 1106 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h deleted file mode 100644 index b6da721d8..000000000 --- a/src/core/hle/service/cam/cam.h +++ /dev/null | |||
| @@ -1,686 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace CAM { | ||
| 15 | |||
| 16 | enum CameraIndex { | ||
| 17 | OuterRightCamera = 0, | ||
| 18 | InnerCamera = 1, | ||
| 19 | OuterLeftCamera = 2, | ||
| 20 | |||
| 21 | NumCameras = 3, | ||
| 22 | }; | ||
| 23 | |||
| 24 | enum class Effect : u8 { | ||
| 25 | None = 0, | ||
| 26 | Mono = 1, | ||
| 27 | Sepia = 2, | ||
| 28 | Negative = 3, | ||
| 29 | Negafilm = 4, | ||
| 30 | Sepia01 = 5, | ||
| 31 | }; | ||
| 32 | |||
| 33 | enum class Flip : u8 { | ||
| 34 | None = 0, | ||
| 35 | Horizontal = 1, | ||
| 36 | Vertical = 2, | ||
| 37 | Reverse = 3, | ||
| 38 | }; | ||
| 39 | |||
| 40 | enum class Size : u8 { | ||
| 41 | VGA = 0, | ||
| 42 | QVGA = 1, | ||
| 43 | QQVGA = 2, | ||
| 44 | CIF = 3, | ||
| 45 | QCIF = 4, | ||
| 46 | DS_LCD = 5, | ||
| 47 | DS_LCDx4 = 6, | ||
| 48 | CTR_TOP_LCD = 7, | ||
| 49 | CTR_BOTTOM_LCD = QVGA, | ||
| 50 | }; | ||
| 51 | |||
| 52 | enum class FrameRate : u8 { | ||
| 53 | Rate_15 = 0, | ||
| 54 | Rate_15_To_5 = 1, | ||
| 55 | Rate_15_To_2 = 2, | ||
| 56 | Rate_10 = 3, | ||
| 57 | Rate_8_5 = 4, | ||
| 58 | Rate_5 = 5, | ||
| 59 | Rate_20 = 6, | ||
| 60 | Rate_20_To_5 = 7, | ||
| 61 | Rate_30 = 8, | ||
| 62 | Rate_30_To_5 = 9, | ||
| 63 | Rate_15_To_10 = 10, | ||
| 64 | Rate_20_To_10 = 11, | ||
| 65 | Rate_30_To_10 = 12, | ||
| 66 | }; | ||
| 67 | |||
| 68 | enum class ShutterSoundType : u8 { | ||
| 69 | Normal = 0, | ||
| 70 | Movie = 1, | ||
| 71 | MovieEnd = 2, | ||
| 72 | }; | ||
| 73 | |||
| 74 | enum class WhiteBalance : u8 { | ||
| 75 | BalanceAuto = 0, | ||
| 76 | Balance3200K = 1, | ||
| 77 | Balance4150K = 2, | ||
| 78 | Balance5200K = 3, | ||
| 79 | Balance6000K = 4, | ||
| 80 | Balance7000K = 5, | ||
| 81 | BalanceMax = 6, | ||
| 82 | BalanceNormal = BalanceAuto, | ||
| 83 | BalanceTungsten = Balance3200K, | ||
| 84 | BalanceWhiteFluorescentLight = Balance4150K, | ||
| 85 | BalanceDaylight = Balance5200K, | ||
| 86 | BalanceCloudy = Balance6000K, | ||
| 87 | BalanceHorizon = Balance6000K, | ||
| 88 | BalanceShade = Balance7000K, | ||
| 89 | }; | ||
| 90 | |||
| 91 | enum class PhotoMode : u8 { | ||
| 92 | Normal = 0, | ||
| 93 | Portrait = 1, | ||
| 94 | Landscape = 2, | ||
| 95 | Nightview = 3, | ||
| 96 | Letter0 = 4, | ||
| 97 | }; | ||
| 98 | |||
| 99 | enum class LensCorrection : u8 { | ||
| 100 | Off = 0, | ||
| 101 | On70 = 1, | ||
| 102 | On90 = 2, | ||
| 103 | Dark = Off, | ||
| 104 | Normal = On70, | ||
| 105 | Bright = On90, | ||
| 106 | }; | ||
| 107 | |||
| 108 | enum class Contrast : u8 { | ||
| 109 | Pattern01 = 1, | ||
| 110 | Pattern02 = 2, | ||
| 111 | Pattern03 = 3, | ||
| 112 | Pattern04 = 4, | ||
| 113 | Pattern05 = 5, | ||
| 114 | Pattern06 = 6, | ||
| 115 | Pattern07 = 7, | ||
| 116 | Pattern08 = 8, | ||
| 117 | Pattern09 = 9, | ||
| 118 | Pattern10 = 10, | ||
| 119 | Pattern11 = 11, | ||
| 120 | Low = Pattern05, | ||
| 121 | Normal = Pattern06, | ||
| 122 | High = Pattern07, | ||
| 123 | }; | ||
| 124 | |||
| 125 | enum class OutputFormat : u8 { | ||
| 126 | YUV422 = 0, | ||
| 127 | RGB565 = 1, | ||
| 128 | }; | ||
| 129 | |||
| 130 | /// Stereo camera calibration data. | ||
| 131 | struct StereoCameraCalibrationData { | ||
| 132 | u8 isValidRotationXY; ///< Bool indicating whether the X and Y rotation data is valid. | ||
| 133 | INSERT_PADDING_BYTES(3); | ||
| 134 | float_le scale; ///< Scale to match the left camera image with the right. | ||
| 135 | float_le rotationZ; ///< Z axis rotation to match the left camera image with the right. | ||
| 136 | float_le translationX; ///< X axis translation to match the left camera image with the right. | ||
| 137 | float_le translationY; ///< Y axis translation to match the left camera image with the right. | ||
| 138 | float_le rotationX; ///< X axis rotation to match the left camera image with the right. | ||
| 139 | float_le rotationY; ///< Y axis rotation to match the left camera image with the right. | ||
| 140 | float_le angleOfViewRight; ///< Right camera angle of view. | ||
| 141 | float_le angleOfViewLeft; ///< Left camera angle of view. | ||
| 142 | float_le distanceToChart; ///< Distance between cameras and measurement chart. | ||
| 143 | float_le distanceCameras; ///< Distance between left and right cameras. | ||
| 144 | s16_le imageWidth; ///< Image width. | ||
| 145 | s16_le imageHeight; ///< Image height. | ||
| 146 | INSERT_PADDING_BYTES(16); | ||
| 147 | }; | ||
| 148 | static_assert(sizeof(StereoCameraCalibrationData) == 64, | ||
| 149 | "StereoCameraCalibrationData structure size is wrong"); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Resolution parameters for the camera. | ||
| 153 | * The native resolution of 3DS camera is 640 * 480. The captured image will be cropped in the | ||
| 154 | * region [crop_x0, crop_x1] * [crop_y0, crop_y1], and then scaled to size width * height as the | ||
| 155 | * output image. Note that all cropping coordinates are inclusive. | ||
| 156 | */ | ||
| 157 | struct Resolution { | ||
| 158 | u16 width; | ||
| 159 | u16 height; | ||
| 160 | u16 crop_x0; | ||
| 161 | u16 crop_y0; | ||
| 162 | u16 crop_x1; | ||
| 163 | u16 crop_y1; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct PackageParameterWithoutContext { | ||
| 167 | u8 camera_select; | ||
| 168 | s8 exposure; | ||
| 169 | WhiteBalance white_balance; | ||
| 170 | s8 sharpness; | ||
| 171 | bool auto_exposure; | ||
| 172 | bool auto_white_balance; | ||
| 173 | FrameRate frame_rate; | ||
| 174 | PhotoMode photo_mode; | ||
| 175 | Contrast contrast; | ||
| 176 | LensCorrection lens_correction; | ||
| 177 | bool noise_filter; | ||
| 178 | u8 padding; | ||
| 179 | s16 auto_exposure_window_x; | ||
| 180 | s16 auto_exposure_window_y; | ||
| 181 | s16 auto_exposure_window_width; | ||
| 182 | s16 auto_exposure_window_height; | ||
| 183 | s16 auto_white_balance_window_x; | ||
| 184 | s16 auto_white_balance_window_y; | ||
| 185 | s16 auto_white_balance_window_width; | ||
| 186 | s16 auto_white_balance_window_height; | ||
| 187 | INSERT_PADDING_WORDS(4); | ||
| 188 | }; | ||
| 189 | |||
| 190 | static_assert(sizeof(PackageParameterWithoutContext) == 44, | ||
| 191 | "PackageParameterCameraWithoutContext structure size is wrong"); | ||
| 192 | |||
| 193 | struct PackageParameterWithContext { | ||
| 194 | u8 camera_select; | ||
| 195 | u8 context_select; | ||
| 196 | Flip flip; | ||
| 197 | Effect effect; | ||
| 198 | Size size; | ||
| 199 | INSERT_PADDING_BYTES(3); | ||
| 200 | INSERT_PADDING_WORDS(3); | ||
| 201 | |||
| 202 | Resolution GetResolution() const; | ||
| 203 | }; | ||
| 204 | |||
| 205 | static_assert(sizeof(PackageParameterWithContext) == 20, | ||
| 206 | "PackageParameterWithContext structure size is wrong"); | ||
| 207 | |||
| 208 | struct PackageParameterWithContextDetail { | ||
| 209 | u8 camera_select; | ||
| 210 | u8 context_select; | ||
| 211 | Flip flip; | ||
| 212 | Effect effect; | ||
| 213 | Resolution resolution; | ||
| 214 | INSERT_PADDING_WORDS(3); | ||
| 215 | |||
| 216 | Resolution GetResolution() const { | ||
| 217 | return resolution; | ||
| 218 | } | ||
| 219 | }; | ||
| 220 | |||
| 221 | static_assert(sizeof(PackageParameterWithContextDetail) == 28, | ||
| 222 | "PackageParameterWithContextDetail structure size is wrong"); | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Starts capturing at the selected port. | ||
| 226 | * Inputs: | ||
| 227 | * 0: 0x00010040 | ||
| 228 | * 1: u8 selected port | ||
| 229 | * Outputs: | ||
| 230 | * 0: 0x00010040 | ||
| 231 | * 1: ResultCode | ||
| 232 | */ | ||
| 233 | void StartCapture(Service::Interface* self); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * Stops capturing from the selected port. | ||
| 237 | * Inputs: | ||
| 238 | * 0: 0x00020040 | ||
| 239 | * 1: u8 selected port | ||
| 240 | * Outputs: | ||
| 241 | * 0: 0x00020040 | ||
| 242 | * 1: ResultCode | ||
| 243 | */ | ||
| 244 | void StopCapture(Service::Interface* self); | ||
| 245 | |||
| 246 | /** | ||
| 247 | * Gets whether the selected port is currently capturing. | ||
| 248 | * Inputs: | ||
| 249 | * 0: 0x00030040 | ||
| 250 | * 1: u8 selected port | ||
| 251 | * Outputs: | ||
| 252 | * 0: 0x00030080 | ||
| 253 | * 1: ResultCode | ||
| 254 | * 2: 0 if not capturing, 1 if capturing | ||
| 255 | */ | ||
| 256 | void IsBusy(Service::Interface* self); | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Clears the buffer of selected ports. | ||
| 260 | * Inputs: | ||
| 261 | * 0: 0x00040040 | ||
| 262 | * 1: u8 selected port | ||
| 263 | * Outputs: | ||
| 264 | * 0: 0x00040040 | ||
| 265 | * 2: ResultCode | ||
| 266 | */ | ||
| 267 | void ClearBuffer(Service::Interface* self); | ||
| 268 | |||
| 269 | /** | ||
| 270 | * Unknown | ||
| 271 | * Inputs: | ||
| 272 | * 0: 0x00050040 | ||
| 273 | * 1: u8 selected port | ||
| 274 | * Outputs: | ||
| 275 | * 0: 0x00050042 | ||
| 276 | * 1: ResultCode | ||
| 277 | * 2: Descriptor: Handle | ||
| 278 | * 3: Event handle | ||
| 279 | */ | ||
| 280 | void GetVsyncInterruptEvent(Service::Interface* self); | ||
| 281 | |||
| 282 | /** | ||
| 283 | * Unknown | ||
| 284 | * Inputs: | ||
| 285 | * 0: 0x00060040 | ||
| 286 | * 1: u8 selected port | ||
| 287 | * Outputs: | ||
| 288 | * 0: 0x00060042 | ||
| 289 | * 1: ResultCode | ||
| 290 | * 2: Descriptor: Handle | ||
| 291 | * 3: Event handle | ||
| 292 | */ | ||
| 293 | void GetBufferErrorInterruptEvent(Service::Interface* self); | ||
| 294 | |||
| 295 | /** | ||
| 296 | * Sets the target buffer to receive a frame of image data and starts the transfer. Each camera | ||
| 297 | * port has its own event to signal the end of the transfer. | ||
| 298 | * | ||
| 299 | * Inputs: | ||
| 300 | * 0: 0x00070102 | ||
| 301 | * 1: Destination address in calling process | ||
| 302 | * 2: u8 selected port | ||
| 303 | * 3: Image size (in bytes) | ||
| 304 | * 4: u16 Transfer unit size (in bytes) | ||
| 305 | * 5: Descriptor: Handle | ||
| 306 | * 6: Handle to destination process | ||
| 307 | * Outputs: | ||
| 308 | * 0: 0x00070042 | ||
| 309 | * 1: ResultCode | ||
| 310 | * 2: Descriptor: Handle | ||
| 311 | * 3: Handle to event signalled when transfer finishes | ||
| 312 | */ | ||
| 313 | void SetReceiving(Service::Interface* self); | ||
| 314 | |||
| 315 | /** | ||
| 316 | * Gets whether the selected port finished receiving a frame. | ||
| 317 | * Inputs: | ||
| 318 | * 0: 0x00080040 | ||
| 319 | * 1: u8 selected port | ||
| 320 | * Outputs: | ||
| 321 | * 0: 0x00080080 | ||
| 322 | * 1: ResultCode | ||
| 323 | * 2: 0 if not finished, 1 if finished | ||
| 324 | */ | ||
| 325 | void IsFinishedReceiving(Service::Interface* self); | ||
| 326 | |||
| 327 | /** | ||
| 328 | * Sets the number of lines the buffer contains. | ||
| 329 | * Inputs: | ||
| 330 | * 0: 0x00090100 | ||
| 331 | * 1: u8 selected port | ||
| 332 | * 2: u16 Number of lines to transfer | ||
| 333 | * 3: u16 Width | ||
| 334 | * 4: u16 Height | ||
| 335 | * Outputs: | ||
| 336 | * 0: 0x00090040 | ||
| 337 | * 1: ResultCode | ||
| 338 | * @todo figure out how the "buffer" actually works. | ||
| 339 | */ | ||
| 340 | void SetTransferLines(Service::Interface* self); | ||
| 341 | |||
| 342 | /** | ||
| 343 | * Gets the maximum number of lines that fit in the buffer | ||
| 344 | * Inputs: | ||
| 345 | * 0: 0x000A0080 | ||
| 346 | * 1: u16 Width | ||
| 347 | * 2: u16 Height | ||
| 348 | * Outputs: | ||
| 349 | * 0: 0x000A0080 | ||
| 350 | * 1: ResultCode | ||
| 351 | * 2: Maximum number of lines that fit in the buffer | ||
| 352 | * @todo figure out how the "buffer" actually works. | ||
| 353 | */ | ||
| 354 | void GetMaxLines(Service::Interface* self); | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Sets the number of bytes the buffer contains. | ||
| 358 | * Inputs: | ||
| 359 | * 0: 0x000B0100 | ||
| 360 | * 1: u8 selected port | ||
| 361 | * 2: u16 Number of bytes to transfer | ||
| 362 | * 3: u16 Width | ||
| 363 | * 4: u16 Height | ||
| 364 | * Outputs: | ||
| 365 | * 0: 0x000B0040 | ||
| 366 | * 1: ResultCode | ||
| 367 | * @todo figure out how the "buffer" actually works. | ||
| 368 | */ | ||
| 369 | void SetTransferBytes(Service::Interface* self); | ||
| 370 | |||
| 371 | /** | ||
| 372 | * Gets the number of bytes to the buffer contains. | ||
| 373 | * Inputs: | ||
| 374 | * 0: 0x000C0040 | ||
| 375 | * 1: u8 selected port | ||
| 376 | * Outputs: | ||
| 377 | * 0: 0x000C0080 | ||
| 378 | * 1: ResultCode | ||
| 379 | * 2: The number of bytes the buffer contains | ||
| 380 | * @todo figure out how the "buffer" actually works. | ||
| 381 | */ | ||
| 382 | void GetTransferBytes(Service::Interface* self); | ||
| 383 | |||
| 384 | /** | ||
| 385 | * Gets the maximum number of bytes that fit in the buffer. | ||
| 386 | * Inputs: | ||
| 387 | * 0: 0x000D0080 | ||
| 388 | * 1: u16 Width | ||
| 389 | * 2: u16 Height | ||
| 390 | * Outputs: | ||
| 391 | * 0: 0x000D0080 | ||
| 392 | * 1: ResultCode | ||
| 393 | * 2: Maximum number of bytes that fit in the buffer | ||
| 394 | * @todo figure out how the "buffer" actually works. | ||
| 395 | */ | ||
| 396 | void GetMaxBytes(Service::Interface* self); | ||
| 397 | |||
| 398 | /** | ||
| 399 | * Enables or disables trimming. | ||
| 400 | * Inputs: | ||
| 401 | * 0: 0x000E0080 | ||
| 402 | * 1: u8 selected port | ||
| 403 | * 2: u8 bool Enable trimming if true | ||
| 404 | * Outputs: | ||
| 405 | * 0: 0x000E0040 | ||
| 406 | * 1: ResultCode | ||
| 407 | */ | ||
| 408 | void SetTrimming(Service::Interface* self); | ||
| 409 | |||
| 410 | /** | ||
| 411 | * Gets whether trimming is enabled. | ||
| 412 | * Inputs: | ||
| 413 | * 0: 0x000F0040 | ||
| 414 | * 1: u8 selected port | ||
| 415 | * Outputs: | ||
| 416 | * 0: 0x000F0080 | ||
| 417 | * 1: ResultCode | ||
| 418 | * 2: u8 bool Enable trimming if true | ||
| 419 | */ | ||
| 420 | void IsTrimming(Service::Interface* self); | ||
| 421 | |||
| 422 | /** | ||
| 423 | * Sets the position to trim. | ||
| 424 | * Inputs: | ||
| 425 | * 0: 0x00100140 | ||
| 426 | * 1: u8 selected port | ||
| 427 | * 2: x start | ||
| 428 | * 3: y start | ||
| 429 | * 4: x end (exclusive) | ||
| 430 | * 5: y end (exclusive) | ||
| 431 | * Outputs: | ||
| 432 | * 0: 0x00100040 | ||
| 433 | * 1: ResultCode | ||
| 434 | */ | ||
| 435 | void SetTrimmingParams(Service::Interface* self); | ||
| 436 | |||
| 437 | /** | ||
| 438 | * Gets the position to trim. | ||
| 439 | * Inputs: | ||
| 440 | * 0: 0x00110040 | ||
| 441 | * 1: u8 selected port | ||
| 442 | * | ||
| 443 | * Outputs: | ||
| 444 | * 0: 0x00110140 | ||
| 445 | * 1: ResultCode | ||
| 446 | * 2: x start | ||
| 447 | * 3: y start | ||
| 448 | * 4: x end (exclusive) | ||
| 449 | * 5: y end (exclusive) | ||
| 450 | */ | ||
| 451 | void GetTrimmingParams(Service::Interface* self); | ||
| 452 | |||
| 453 | /** | ||
| 454 | * Sets the position to trim by giving the width and height. The trimming window is always at the | ||
| 455 | * center. | ||
| 456 | * Inputs: | ||
| 457 | * 0: 0x00120140 | ||
| 458 | * 1: u8 selected port | ||
| 459 | * 2: s16 Trim width | ||
| 460 | * 3: s16 Trim height | ||
| 461 | * 4: s16 Camera width | ||
| 462 | * 5: s16 Camera height | ||
| 463 | * Outputs: | ||
| 464 | * 0: 0x00120040 | ||
| 465 | * 1: ResultCode | ||
| 466 | */ | ||
| 467 | void SetTrimmingParamsCenter(Service::Interface* self); | ||
| 468 | |||
| 469 | /** | ||
| 470 | * Selects up to two physical cameras to enable. | ||
| 471 | * Inputs: | ||
| 472 | * 0: 0x00130040 | ||
| 473 | * 1: u8 selected camera | ||
| 474 | * Outputs: | ||
| 475 | * 0: 0x00130040 | ||
| 476 | * 1: ResultCode | ||
| 477 | */ | ||
| 478 | void Activate(Service::Interface* self); | ||
| 479 | |||
| 480 | /** | ||
| 481 | * Switches the context of camera settings. | ||
| 482 | * Inputs: | ||
| 483 | * 0: 0x00140080 | ||
| 484 | * 1: u8 selected camera | ||
| 485 | * 2: u8 selected context | ||
| 486 | * Outputs: | ||
| 487 | * 0: 0x00140040 | ||
| 488 | * 1: ResultCode | ||
| 489 | */ | ||
| 490 | void SwitchContext(Service::Interface* self); | ||
| 491 | |||
| 492 | /** | ||
| 493 | * Sets flipping of images | ||
| 494 | * Inputs: | ||
| 495 | * 0: 0x001D00C0 | ||
| 496 | * 1: u8 selected camera | ||
| 497 | * 2: u8 Type of flipping to perform (`Flip` enum) | ||
| 498 | * 3: u8 selected context | ||
| 499 | * Outputs: | ||
| 500 | * 0: 0x001D0040 | ||
| 501 | * 1: ResultCode | ||
| 502 | */ | ||
| 503 | void FlipImage(Service::Interface* self); | ||
| 504 | |||
| 505 | /** | ||
| 506 | * Sets camera resolution from custom parameters. For more details see the Resolution struct. | ||
| 507 | * Inputs: | ||
| 508 | * 0: 0x001E0200 | ||
| 509 | * 1: u8 selected camera | ||
| 510 | * 2: width | ||
| 511 | * 3: height | ||
| 512 | * 4: crop x0 | ||
| 513 | * 5: crop y0 | ||
| 514 | * 6: crop x1 | ||
| 515 | * 7: crop y1 | ||
| 516 | * 8: u8 selected context | ||
| 517 | * Outputs: | ||
| 518 | * 0: 0x001E0040 | ||
| 519 | * 1: ResultCode | ||
| 520 | */ | ||
| 521 | void SetDetailSize(Service::Interface* self); | ||
| 522 | |||
| 523 | /** | ||
| 524 | * Sets camera resolution from preset resolution parameters. | ||
| 525 | * Inputs: | ||
| 526 | * 0: 0x001F00C0 | ||
| 527 | * 1: u8 selected camera | ||
| 528 | * 2: u8 Camera frame resolution (`Size` enum) | ||
| 529 | * 3: u8 selected context | ||
| 530 | * Outputs: | ||
| 531 | * 0: 0x001F0040 | ||
| 532 | * 1: ResultCode | ||
| 533 | */ | ||
| 534 | void SetSize(Service::Interface* self); | ||
| 535 | |||
| 536 | /** | ||
| 537 | * Sets camera framerate. | ||
| 538 | * Inputs: | ||
| 539 | * 0: 0x00200080 | ||
| 540 | * 1: u8 selected camera | ||
| 541 | * 2: u8 Camera framerate (`FrameRate` enum) | ||
| 542 | * Outputs: | ||
| 543 | * 0: 0x00200040 | ||
| 544 | * 1: ResultCode | ||
| 545 | */ | ||
| 546 | void SetFrameRate(Service::Interface* self); | ||
| 547 | |||
| 548 | /** | ||
| 549 | * Sets effect on the output image | ||
| 550 | * Inputs: | ||
| 551 | * 0: 0x002200C0 | ||
| 552 | * 1: u8 selected camera | ||
| 553 | * 2: u8 image effect (`Effect` enum) | ||
| 554 | * 3: u8 selected context | ||
| 555 | * Outputs: | ||
| 556 | * 0: 0x00220040 | ||
| 557 | * 1: ResultCode | ||
| 558 | */ | ||
| 559 | void SetEffect(Service::Interface* self); | ||
| 560 | |||
| 561 | /** | ||
| 562 | * Sets format of the output image | ||
| 563 | * Inputs: | ||
| 564 | * 0: 0x002500C0 | ||
| 565 | * 1: u8 selected camera | ||
| 566 | * 2: u8 image format (`OutputFormat` enum) | ||
| 567 | * 3: u8 selected context | ||
| 568 | * Outputs: | ||
| 569 | * 0: 0x00250040 | ||
| 570 | * 1: ResultCode | ||
| 571 | */ | ||
| 572 | void SetOutputFormat(Service::Interface* self); | ||
| 573 | |||
| 574 | /** | ||
| 575 | * Synchronizes the V-Sync timing of two cameras. | ||
| 576 | * Inputs: | ||
| 577 | * 0: 0x00290080 | ||
| 578 | * 1: u8 selected camera 1 | ||
| 579 | * 2: u8 selected camera 2 | ||
| 580 | * Outputs: | ||
| 581 | * 0: 0x00280040 | ||
| 582 | * 1: ResultCode | ||
| 583 | */ | ||
| 584 | void SynchronizeVsyncTiming(Service::Interface* self); | ||
| 585 | |||
| 586 | /** | ||
| 587 | * Returns calibration data relating the outside cameras to eachother, for use in AR applications. | ||
| 588 | * | ||
| 589 | * Inputs: | ||
| 590 | * 0: 0x002B0000 | ||
| 591 | * Outputs: | ||
| 592 | * 0: 0x002B0440 | ||
| 593 | * 1: ResultCode | ||
| 594 | * 2-17: `StereoCameraCalibrationData` structure with calibration values | ||
| 595 | */ | ||
| 596 | void GetStereoCameraCalibrationData(Service::Interface* self); | ||
| 597 | |||
| 598 | /** | ||
| 599 | * Batch-configures context-free settings. | ||
| 600 | * | ||
| 601 | * Inputs: | ||
| 602 | * 0: 0x003302C0 | ||
| 603 | * 1-7: struct PachageParameterWithoutContext | ||
| 604 | * 8-11: unused | ||
| 605 | * Outputs: | ||
| 606 | * 0: 0x00330040 | ||
| 607 | * 1: ResultCode | ||
| 608 | */ | ||
| 609 | void SetPackageParameterWithoutContext(Service::Interface* self); | ||
| 610 | |||
| 611 | /** | ||
| 612 | * Batch-configures context-related settings with preset resolution parameters. | ||
| 613 | * | ||
| 614 | * Inputs: | ||
| 615 | * 0: 0x00340140 | ||
| 616 | * 1-2: struct PackageParameterWithContext | ||
| 617 | * 3-5: unused | ||
| 618 | * Outputs: | ||
| 619 | * 0: 0x00340040 | ||
| 620 | * 1: ResultCode | ||
| 621 | */ | ||
| 622 | void SetPackageParameterWithContext(Service::Interface* self); | ||
| 623 | |||
| 624 | /** | ||
| 625 | * Batch-configures context-related settings with custom resolution parameters | ||
| 626 | * | ||
| 627 | * Inputs: | ||
| 628 | * 0: 0x003501C0 | ||
| 629 | * 1-4: struct PackageParameterWithContextDetail | ||
| 630 | * 5-7: unused | ||
| 631 | * Outputs: | ||
| 632 | * 0: 0x00350040 | ||
| 633 | * 1: ResultCode | ||
| 634 | */ | ||
| 635 | void SetPackageParameterWithContextDetail(Service::Interface* self); | ||
| 636 | |||
| 637 | /** | ||
| 638 | * Unknown | ||
| 639 | * Inputs: | ||
| 640 | * 0: 0x00360000 | ||
| 641 | * Outputs: | ||
| 642 | * 0: 0x00360080 | ||
| 643 | * 1: ResultCode | ||
| 644 | * 2: ? | ||
| 645 | */ | ||
| 646 | void GetSuitableY2rStandardCoefficient(Service::Interface* self); | ||
| 647 | |||
| 648 | /** | ||
| 649 | * Unknown | ||
| 650 | * Inputs: | ||
| 651 | * 0: 0x00380040 | ||
| 652 | * 1: u8 Sound ID | ||
| 653 | * Outputs: | ||
| 654 | * 0: 0x00380040 | ||
| 655 | * 1: ResultCode | ||
| 656 | */ | ||
| 657 | void PlayShutterSound(Service::Interface* self); | ||
| 658 | |||
| 659 | /** | ||
| 660 | * Initializes the camera driver. Must be called before using other functions. | ||
| 661 | * Inputs: | ||
| 662 | * 0: 0x00390000 | ||
| 663 | * Outputs: | ||
| 664 | * 0: 0x00390040 | ||
| 665 | * 1: ResultCode | ||
| 666 | */ | ||
| 667 | void DriverInitialize(Service::Interface* self); | ||
| 668 | |||
| 669 | /** | ||
| 670 | * Shuts down the camera driver. | ||
| 671 | * Inputs: | ||
| 672 | * 0: 0x003A0000 | ||
| 673 | * Outputs: | ||
| 674 | * 0: 0x003A0040 | ||
| 675 | * 1: ResultCode | ||
| 676 | */ | ||
| 677 | void DriverFinalize(Service::Interface* self); | ||
| 678 | |||
| 679 | /// Initialize CAM service(s) | ||
| 680 | void Init(); | ||
| 681 | |||
| 682 | /// Shutdown CAM service(s) | ||
| 683 | void Shutdown(); | ||
| 684 | |||
| 685 | } // namespace CAM | ||
| 686 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp deleted file mode 100644 index 93b047c1a..000000000 --- a/src/core/hle/service/cam/cam_c.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cam/cam_c.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace CAM { | ||
| 9 | |||
| 10 | // Empty arrays are illegal -- commented out until an entry is added. | ||
| 11 | // const Interface::FunctionInfo FunctionTable[] = { }; | ||
| 12 | |||
| 13 | CAM_C_Interface::CAM_C_Interface() { | ||
| 14 | // Register(FunctionTable); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace CAM | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h deleted file mode 100644 index 6b296c00d..000000000 --- a/src/core/hle/service/cam/cam_c.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CAM { | ||
| 11 | |||
| 12 | class CAM_C_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | CAM_C_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cam:c"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CAM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp deleted file mode 100644 index 2ba853606..000000000 --- a/src/core/hle/service/cam/cam_q.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cam/cam_q.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace CAM { | ||
| 9 | |||
| 10 | // Empty arrays are illegal -- commented out until an entry is added. | ||
| 11 | // const Interface::FunctionInfo FunctionTable[] = { }; | ||
| 12 | |||
| 13 | CAM_Q_Interface::CAM_Q_Interface() { | ||
| 14 | // Register(FunctionTable); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace CAM | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h deleted file mode 100644 index 07cc12534..000000000 --- a/src/core/hle/service/cam/cam_q.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CAM { | ||
| 11 | |||
| 12 | class CAM_Q_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | CAM_Q_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cam:q"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CAM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp deleted file mode 100644 index f1c6da587..000000000 --- a/src/core/hle/service/cam/cam_s.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cam/cam_s.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace CAM { | ||
| 9 | |||
| 10 | // Empty arrays are illegal -- commented out until an entry is added. | ||
| 11 | // const Interface::FunctionInfo FunctionTable[] = { }; | ||
| 12 | |||
| 13 | CAM_S_Interface::CAM_S_Interface() { | ||
| 14 | // Register(FunctionTable); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace CAM | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h deleted file mode 100644 index 0a5d6fca2..000000000 --- a/src/core/hle/service/cam/cam_s.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CAM { | ||
| 11 | |||
| 12 | class CAM_S_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | CAM_S_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cam:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CAM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp deleted file mode 100644 index 251c1e6d4..000000000 --- a/src/core/hle/service/cam/cam_u.cpp +++ /dev/null | |||
| @@ -1,81 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cam/cam.h" | ||
| 6 | #include "core/hle/service/cam/cam_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace CAM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010040, StartCapture, "StartCapture"}, | ||
| 13 | {0x00020040, StopCapture, "StopCapture"}, | ||
| 14 | {0x00030040, IsBusy, "IsBusy"}, | ||
| 15 | {0x00040040, ClearBuffer, "ClearBuffer"}, | ||
| 16 | {0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, | ||
| 17 | {0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, | ||
| 18 | {0x00070102, SetReceiving, "SetReceiving"}, | ||
| 19 | {0x00080040, IsFinishedReceiving, "IsFinishedReceiving"}, | ||
| 20 | {0x00090100, SetTransferLines, "SetTransferLines"}, | ||
| 21 | {0x000A0080, GetMaxLines, "GetMaxLines"}, | ||
| 22 | {0x000B0100, SetTransferBytes, "SetTransferBytes"}, | ||
| 23 | {0x000C0040, GetTransferBytes, "GetTransferBytes"}, | ||
| 24 | {0x000D0080, GetMaxBytes, "GetMaxBytes"}, | ||
| 25 | {0x000E0080, SetTrimming, "SetTrimming"}, | ||
| 26 | {0x000F0040, IsTrimming, "IsTrimming"}, | ||
| 27 | {0x00100140, SetTrimmingParams, "SetTrimmingParams"}, | ||
| 28 | {0x00110040, GetTrimmingParams, "GetTrimmingParams"}, | ||
| 29 | {0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, | ||
| 30 | {0x00130040, Activate, "Activate"}, | ||
| 31 | {0x00140080, SwitchContext, "SwitchContext"}, | ||
| 32 | {0x00150080, nullptr, "SetExposure"}, | ||
| 33 | {0x00160080, nullptr, "SetWhiteBalance"}, | ||
| 34 | {0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"}, | ||
| 35 | {0x00180080, nullptr, "SetSharpness"}, | ||
| 36 | {0x00190080, nullptr, "SetAutoExposure"}, | ||
| 37 | {0x001A0040, nullptr, "IsAutoExposure"}, | ||
| 38 | {0x001B0080, nullptr, "SetAutoWhiteBalance"}, | ||
| 39 | {0x001C0040, nullptr, "IsAutoWhiteBalance"}, | ||
| 40 | {0x001D00C0, FlipImage, "FlipImage"}, | ||
| 41 | {0x001E0200, SetDetailSize, "SetDetailSize"}, | ||
| 42 | {0x001F00C0, SetSize, "SetSize"}, | ||
| 43 | {0x00200080, SetFrameRate, "SetFrameRate"}, | ||
| 44 | {0x00210080, nullptr, "SetPhotoMode"}, | ||
| 45 | {0x002200C0, SetEffect, "SetEffect"}, | ||
| 46 | {0x00230080, nullptr, "SetContrast"}, | ||
| 47 | {0x00240080, nullptr, "SetLensCorrection"}, | ||
| 48 | {0x002500C0, SetOutputFormat, "SetOutputFormat"}, | ||
| 49 | {0x00260140, nullptr, "SetAutoExposureWindow"}, | ||
| 50 | {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, | ||
| 51 | {0x00280080, nullptr, "SetNoiseFilter"}, | ||
| 52 | {0x00290080, SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, | ||
| 53 | {0x002A0080, nullptr, "GetLatestVsyncTiming"}, | ||
| 54 | {0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, | ||
| 55 | {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, | ||
| 56 | {0x002D00C0, nullptr, "WriteRegisterI2c"}, | ||
| 57 | {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, | ||
| 58 | {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, | ||
| 59 | {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, | ||
| 60 | {0x00310180, nullptr, "SetImageQualityCalibrationData"}, | ||
| 61 | {0x00320000, nullptr, "GetImageQualityCalibrationData"}, | ||
| 62 | {0x003302C0, SetPackageParameterWithoutContext, "SetPackageParameterWithoutContext"}, | ||
| 63 | {0x00340140, SetPackageParameterWithContext, "SetPackageParameterWithContext"}, | ||
| 64 | {0x003501C0, SetPackageParameterWithContextDetail, "SetPackageParameterWithContextDetail"}, | ||
| 65 | {0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"}, | ||
| 66 | {0x00370202, nullptr, "PlayShutterSoundWithWave"}, | ||
| 67 | {0x00380040, PlayShutterSound, "PlayShutterSound"}, | ||
| 68 | {0x00390000, DriverInitialize, "DriverInitialize"}, | ||
| 69 | {0x003A0000, DriverFinalize, "DriverFinalize"}, | ||
| 70 | {0x003B0000, nullptr, "GetActivatedCamera"}, | ||
| 71 | {0x003C0000, nullptr, "GetSleepCamera"}, | ||
| 72 | {0x003D0040, nullptr, "SetSleepCamera"}, | ||
| 73 | {0x003E0040, nullptr, "SetBrightnessSynchronization"}, | ||
| 74 | }; | ||
| 75 | |||
| 76 | CAM_U_Interface::CAM_U_Interface() { | ||
| 77 | Register(FunctionTable); | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace CAM | ||
| 81 | } // namespace Service | ||
diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h deleted file mode 100644 index 369264037..000000000 --- a/src/core/hle/service/cam/cam_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CAM { | ||
| 11 | |||
| 12 | class CAM_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | CAM_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cam:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CAM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp deleted file mode 100644 index 421006a9e..000000000 --- a/src/core/hle/service/cecd/cecd.cpp +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc.h" | ||
| 7 | #include "core/hle/kernel/event.h" | ||
| 8 | #include "core/hle/kernel/handle_table.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/cecd/cecd.h" | ||
| 11 | #include "core/hle/service/cecd/cecd_ndm.h" | ||
| 12 | #include "core/hle/service/cecd/cecd_s.h" | ||
| 13 | #include "core/hle/service/cecd/cecd_u.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace CECD { | ||
| 18 | |||
| 19 | static Kernel::SharedPtr<Kernel::Event> cecinfo_event; | ||
| 20 | static Kernel::SharedPtr<Kernel::Event> change_state_event; | ||
| 21 | |||
| 22 | void GetCecStateAbbreviated(Service::Interface* self) { | ||
| 23 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 24 | |||
| 25 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 26 | cmd_buff[2] = static_cast<u32>(CecStateAbbreviated::CEC_STATE_ABBREV_IDLE); | ||
| 27 | |||
| 28 | LOG_WARNING(Service_CECD, "(STUBBED) called"); | ||
| 29 | } | ||
| 30 | |||
| 31 | void GetCecInfoEventHandle(Service::Interface* self) { | ||
| 32 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 33 | |||
| 34 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 35 | cmd_buff[3] = Kernel::g_handle_table.Create(cecinfo_event).Unwrap(); // Event handle | ||
| 36 | |||
| 37 | LOG_WARNING(Service_CECD, "(STUBBED) called"); | ||
| 38 | } | ||
| 39 | |||
| 40 | void GetChangeStateEventHandle(Service::Interface* self) { | ||
| 41 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 42 | |||
| 43 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 44 | cmd_buff[3] = Kernel::g_handle_table.Create(change_state_event).Unwrap(); // Event handle | ||
| 45 | |||
| 46 | LOG_WARNING(Service_CECD, "(STUBBED) called"); | ||
| 47 | } | ||
| 48 | |||
| 49 | void Init() { | ||
| 50 | AddService(new CECD_NDM); | ||
| 51 | AddService(new CECD_S); | ||
| 52 | AddService(new CECD_U); | ||
| 53 | |||
| 54 | cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); | ||
| 55 | change_state_event = | ||
| 56 | Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event"); | ||
| 57 | } | ||
| 58 | |||
| 59 | void Shutdown() { | ||
| 60 | cecinfo_event = nullptr; | ||
| 61 | change_state_event = nullptr; | ||
| 62 | } | ||
| 63 | |||
| 64 | } // namespace CECD | ||
| 65 | |||
| 66 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h deleted file mode 100644 index ea97f9266..000000000 --- a/src/core/hle/service/cecd/cecd.h +++ /dev/null | |||
| @@ -1,60 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | class Interface; | ||
| 10 | |||
| 11 | namespace CECD { | ||
| 12 | |||
| 13 | enum class CecStateAbbreviated { | ||
| 14 | CEC_STATE_ABBREV_IDLE = 1, ///< Corresponds to CEC_STATE_IDLE | ||
| 15 | CEC_STATE_ABBREV_NOT_LOCAL = 2, ///< Corresponds to CEC_STATEs *FINISH*, *POST, and OVER_BOSS | ||
| 16 | CEC_STATE_ABBREV_SCANNING = 3, ///< Corresponds to CEC_STATE_SCANNING | ||
| 17 | CEC_STATE_ABBREV_WLREADY = | ||
| 18 | 4, ///< Corresponds to CEC_STATE_WIRELESS_READY when some unknown bool is true | ||
| 19 | CEC_STATE_ABBREV_OTHER = 5, ///< Corresponds to CEC_STATEs besides *FINISH*, *POST, and | ||
| 20 | /// OVER_BOSS and those listed here | ||
| 21 | }; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * GetCecStateAbbreviated service function | ||
| 25 | * Inputs: | ||
| 26 | * 0: 0x000E0000 | ||
| 27 | * Outputs: | ||
| 28 | * 1: ResultCode | ||
| 29 | * 2: CecStateAbbreviated | ||
| 30 | */ | ||
| 31 | void GetCecStateAbbreviated(Service::Interface* self); | ||
| 32 | |||
| 33 | /** | ||
| 34 | * GetCecInfoEventHandle service function | ||
| 35 | * Inputs: | ||
| 36 | * 0: 0x000F0000 | ||
| 37 | * Outputs: | ||
| 38 | * 1: ResultCode | ||
| 39 | * 3: Event Handle | ||
| 40 | */ | ||
| 41 | void GetCecInfoEventHandle(Service::Interface* self); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * GetChangeStateEventHandle service function | ||
| 45 | * Inputs: | ||
| 46 | * 0: 0x00100000 | ||
| 47 | * Outputs: | ||
| 48 | * 1: ResultCode | ||
| 49 | * 3: Event Handle | ||
| 50 | */ | ||
| 51 | void GetChangeStateEventHandle(Service::Interface* self); | ||
| 52 | |||
| 53 | /// Initialize CECD service(s) | ||
| 54 | void Init(); | ||
| 55 | |||
| 56 | /// Shutdown CECD service(s) | ||
| 57 | void Shutdown(); | ||
| 58 | |||
| 59 | } // namespace CECD | ||
| 60 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp deleted file mode 100644 index 7baf93750..000000000 --- a/src/core/hle/service/cecd/cecd_ndm.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cecd/cecd.h" | ||
| 6 | #include "core/hle/service/cecd/cecd_ndm.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace CECD { | ||
| 10 | |||
| 11 | static const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010000, nullptr, "Initialize"}, | ||
| 13 | {0x00020000, nullptr, "Deinitialize"}, | ||
| 14 | {0x00030000, nullptr, "ResumeDaemon"}, | ||
| 15 | {0x00040040, nullptr, "SuspendDaemon"}, | ||
| 16 | }; | ||
| 17 | |||
| 18 | CECD_NDM::CECD_NDM() { | ||
| 19 | Register(FunctionTable); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace CECD | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h deleted file mode 100644 index 2e2e50ada..000000000 --- a/src/core/hle/service/cecd/cecd_ndm.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CECD { | ||
| 11 | |||
| 12 | class CECD_NDM : public Interface { | ||
| 13 | public: | ||
| 14 | CECD_NDM(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cecd:ndm"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CECD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp deleted file mode 100644 index eacda7d41..000000000 --- a/src/core/hle/service/cecd/cecd_s.cpp +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cecd/cecd.h" | ||
| 6 | #include "core/hle/service/cecd/cecd_s.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace CECD { | ||
| 10 | |||
| 11 | static const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // cecd:u shared commands | ||
| 13 | {0x000100C2, nullptr, "OpenRawFile"}, | ||
| 14 | {0x00020042, nullptr, "ReadRawFile"}, | ||
| 15 | {0x00030104, nullptr, "ReadMessage"}, | ||
| 16 | {0x00040106, nullptr, "ReadMessageWithHMAC"}, | ||
| 17 | {0x00050042, nullptr, "WriteRawFile"}, | ||
| 18 | {0x00060104, nullptr, "WriteMessage"}, | ||
| 19 | {0x00070106, nullptr, "WriteMessageWithHMAC"}, | ||
| 20 | {0x00080102, nullptr, "Delete"}, | ||
| 21 | {0x000A00C4, nullptr, "GetSystemInfo"}, | ||
| 22 | {0x000B0040, nullptr, "RunCommand"}, | ||
| 23 | {0x000C0040, nullptr, "RunCommandAlt"}, | ||
| 24 | {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"}, | ||
| 25 | {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"}, | ||
| 26 | {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"}, | ||
| 27 | {0x00110104, nullptr, "OpenAndWrite"}, | ||
| 28 | {0x00120104, nullptr, "OpenAndRead"}, | ||
| 29 | }; | ||
| 30 | |||
| 31 | CECD_S::CECD_S() { | ||
| 32 | Register(FunctionTable); | ||
| 33 | } | ||
| 34 | |||
| 35 | } // namespace CECD | ||
| 36 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h deleted file mode 100644 index ab6c6789a..000000000 --- a/src/core/hle/service/cecd/cecd_s.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CECD { | ||
| 11 | |||
| 12 | class CECD_S : public Interface { | ||
| 13 | public: | ||
| 14 | CECD_S(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cecd:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CECD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp deleted file mode 100644 index 3ed864f0b..000000000 --- a/src/core/hle/service/cecd/cecd_u.cpp +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/cecd/cecd.h" | ||
| 6 | #include "core/hle/service/cecd/cecd_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace CECD { | ||
| 10 | |||
| 11 | static const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // cecd:u shared commands | ||
| 13 | {0x000100C2, nullptr, "OpenRawFile"}, | ||
| 14 | {0x00020042, nullptr, "ReadRawFile"}, | ||
| 15 | {0x00030104, nullptr, "ReadMessage"}, | ||
| 16 | {0x00040106, nullptr, "ReadMessageWithHMAC"}, | ||
| 17 | {0x00050042, nullptr, "WriteRawFile"}, | ||
| 18 | {0x00060104, nullptr, "WriteMessage"}, | ||
| 19 | {0x00070106, nullptr, "WriteMessageWithHMAC"}, | ||
| 20 | {0x00080102, nullptr, "Delete"}, | ||
| 21 | {0x000A00C4, nullptr, "GetSystemInfo"}, | ||
| 22 | {0x000B0040, nullptr, "RunCommand"}, | ||
| 23 | {0x000C0040, nullptr, "RunCommandAlt"}, | ||
| 24 | {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"}, | ||
| 25 | {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"}, | ||
| 26 | {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"}, | ||
| 27 | {0x00110104, nullptr, "OpenAndWrite"}, | ||
| 28 | {0x00120104, nullptr, "OpenAndRead"}, | ||
| 29 | }; | ||
| 30 | |||
| 31 | CECD_U::CECD_U() { | ||
| 32 | Register(FunctionTable); | ||
| 33 | } | ||
| 34 | |||
| 35 | } // namespace CECD | ||
| 36 | } // namespace Service | ||
diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h deleted file mode 100644 index 16e874ff5..000000000 --- a/src/core/hle/service/cecd/cecd_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CECD { | ||
| 11 | |||
| 12 | class CECD_U : public Interface { | ||
| 13 | public: | ||
| 14 | CECD_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "cecd:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CECD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp deleted file mode 100644 index aac903ccb..000000000 --- a/src/core/hle/service/csnd_snd.cpp +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/alignment.h" | ||
| 7 | #include "core/hle/ipc.h" | ||
| 8 | #include "core/hle/kernel/handle_table.h" | ||
| 9 | #include "core/hle/kernel/mutex.h" | ||
| 10 | #include "core/hle/kernel/shared_memory.h" | ||
| 11 | #include "core/hle/service/csnd_snd.h" | ||
| 12 | #include "core/memory.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace CSND { | ||
| 16 | |||
| 17 | struct Type0Command { | ||
| 18 | // command id and next command offset | ||
| 19 | u32 command_id; | ||
| 20 | u32 finished; | ||
| 21 | u32 flags; | ||
| 22 | u8 parameters[20]; | ||
| 23 | }; | ||
| 24 | static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong"); | ||
| 25 | |||
| 26 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; | ||
| 27 | static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * CSND_SND::Initialize service function | ||
| 31 | * Inputs: | ||
| 32 | * 0 : Header Code[0x00010140] | ||
| 33 | * 1 : Shared memory block size, for mem-block creation | ||
| 34 | * Outputs: | ||
| 35 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 36 | * 2 : Handle-list header | ||
| 37 | * 3 : Mutex handle | ||
| 38 | * 4 : Shared memory block handle | ||
| 39 | */ | ||
| 40 | static void Initialize(Interface* self) { | ||
| 41 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 42 | |||
| 43 | u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE); | ||
| 44 | |||
| 45 | using Kernel::MemoryPermission; | ||
| 46 | shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite, | ||
| 47 | MemoryPermission::ReadWrite, 0, | ||
| 48 | Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); | ||
| 49 | |||
| 50 | mutex = Kernel::Mutex::Create(false, 0, "CSND:mutex"); | ||
| 51 | |||
| 52 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 53 | cmd_buff[2] = IPC::CopyHandleDesc(2); | ||
| 54 | cmd_buff[3] = Kernel::g_handle_table.Create(mutex).Unwrap(); | ||
| 55 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).Unwrap(); | ||
| 56 | |||
| 57 | LOG_WARNING(Service_CSND, "(STUBBED) called"); | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * CSND_SND::Shutdown service function | ||
| 62 | * Inputs: | ||
| 63 | * 0 : Header Code[0x00020000] | ||
| 64 | * Outputs: | ||
| 65 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 66 | */ | ||
| 67 | static void Shutdown(Interface* self) { | ||
| 68 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 69 | |||
| 70 | shared_memory = nullptr; | ||
| 71 | mutex = nullptr; | ||
| 72 | |||
| 73 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 74 | LOG_WARNING(Service_CSND, "(STUBBED) called"); | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * CSND_SND::ExecuteCommands service function | ||
| 79 | * Inputs: | ||
| 80 | * 0 : Header Code[0x00030040] | ||
| 81 | * 1 : Command offset in shared memory. | ||
| 82 | * Outputs: | ||
| 83 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 84 | * 2 : Available channel bit mask | ||
| 85 | */ | ||
| 86 | static void ExecuteCommands(Interface* self) { | ||
| 87 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 88 | |||
| 89 | if (shared_memory == nullptr) { | ||
| 90 | cmd_buff[1] = 1; | ||
| 91 | LOG_ERROR(Service_CSND, "called, shared memory not allocated"); | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | |||
| 95 | VAddr addr = cmd_buff[1]; | ||
| 96 | u8* ptr = shared_memory->GetPointer(addr); | ||
| 97 | |||
| 98 | Type0Command command; | ||
| 99 | std::memcpy(&command, ptr, sizeof(Type0Command)); | ||
| 100 | command.finished |= 1; | ||
| 101 | std::memcpy(ptr, &command, sizeof(Type0Command)); | ||
| 102 | |||
| 103 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 104 | |||
| 105 | LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x%08X", addr); | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * CSND_SND::AcquireSoundChannels service function | ||
| 110 | * Inputs: | ||
| 111 | * 0 : Header Code[0x00050000] | ||
| 112 | * Outputs: | ||
| 113 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 114 | * 2 : Available channel bit mask | ||
| 115 | */ | ||
| 116 | static void AcquireSoundChannels(Interface* self) { | ||
| 117 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 118 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 119 | cmd_buff[2] = 0xFFFFFF00; | ||
| 120 | LOG_WARNING(Service_CSND, "(STUBBED) called"); | ||
| 121 | } | ||
| 122 | |||
| 123 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 124 | {0x00010140, Initialize, "Initialize"}, | ||
| 125 | {0x00020000, Shutdown, "Shutdown"}, | ||
| 126 | {0x00030040, ExecuteCommands, "ExecuteCommands"}, | ||
| 127 | {0x00040080, nullptr, "ExecuteType1Commands"}, | ||
| 128 | {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"}, | ||
| 129 | {0x00060000, nullptr, "ReleaseSoundChannels"}, | ||
| 130 | {0x00070000, nullptr, "AcquireCaptureDevice"}, | ||
| 131 | {0x00080040, nullptr, "ReleaseCaptureDevice"}, | ||
| 132 | {0x00090082, nullptr, "FlushDataCache"}, | ||
| 133 | {0x000A0082, nullptr, "StoreDataCache"}, | ||
| 134 | {0x000B0082, nullptr, "InvalidateDataCache"}, | ||
| 135 | {0x000C0000, nullptr, "Reset"}, | ||
| 136 | }; | ||
| 137 | |||
| 138 | CSND_SND::CSND_SND() { | ||
| 139 | Register(FunctionTable); | ||
| 140 | } | ||
| 141 | |||
| 142 | } // namespace CSND | ||
| 143 | } // namespace Service | ||
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h deleted file mode 100644 index ca6d4513e..000000000 --- a/src/core/hle/service/csnd_snd.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace CSND { | ||
| 11 | |||
| 12 | class CSND_SND final : public Interface { | ||
| 13 | public: | ||
| 14 | CSND_SND(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "csnd:SND"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace CSND | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp.cpp b/src/core/hle/service/dlp/dlp.cpp deleted file mode 100644 index 8f4b67a5d..000000000 --- a/src/core/hle/service/dlp/dlp.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/dlp/dlp.h" | ||
| 6 | #include "core/hle/service/dlp/dlp_clnt.h" | ||
| 7 | #include "core/hle/service/dlp/dlp_fkcl.h" | ||
| 8 | #include "core/hle/service/dlp/dlp_srvr.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace DLP { | ||
| 13 | |||
| 14 | void Init() { | ||
| 15 | AddService(new DLP_CLNT_Interface); | ||
| 16 | AddService(new DLP_FKCL_Interface); | ||
| 17 | AddService(new DLP_SRVR_Interface); | ||
| 18 | } | ||
| 19 | |||
| 20 | void Shutdown() {} | ||
| 21 | |||
| 22 | } // namespace DLP | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h deleted file mode 100644 index 3185fe322..000000000 --- a/src/core/hle/service/dlp/dlp.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace DLP { | ||
| 9 | |||
| 10 | /// Initializes the DLP services. | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | /// Shuts down the DLP services. | ||
| 14 | void Shutdown(); | ||
| 15 | |||
| 16 | } // namespace DLP | ||
| 17 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp deleted file mode 100644 index 6f2bf2061..000000000 --- a/src/core/hle/service/dlp/dlp_clnt.cpp +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/dlp/dlp_clnt.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace DLP { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x000100C3, nullptr, "Initialize"}, | ||
| 12 | {0x00020000, nullptr, "Finalize"}, | ||
| 13 | {0x00030000, nullptr, "GetEventDesc"}, | ||
| 14 | {0x00040000, nullptr, "GetChannel"}, | ||
| 15 | {0x00050180, nullptr, "StartScan"}, | ||
| 16 | {0x00060000, nullptr, "StopScan"}, | ||
| 17 | {0x00070080, nullptr, "GetServerInfo"}, | ||
| 18 | {0x00080100, nullptr, "GetTitleInfo"}, | ||
| 19 | {0x00090040, nullptr, "GetTitleInfoInOrder"}, | ||
| 20 | {0x000A0080, nullptr, "DeleteScanInfo"}, | ||
| 21 | {0x000B0100, nullptr, "PrepareForSystemDownload"}, | ||
| 22 | {0x000C0000, nullptr, "StartSystemDownload"}, | ||
| 23 | {0x000D0100, nullptr, "StartTitleDownload"}, | ||
| 24 | {0x000E0000, nullptr, "GetMyStatus"}, | ||
| 25 | {0x000F0040, nullptr, "GetConnectingNodes"}, | ||
| 26 | {0x00100040, nullptr, "GetNodeInfo"}, | ||
| 27 | {0x00110000, nullptr, "GetWirelessRebootPassphrase"}, | ||
| 28 | {0x00120000, nullptr, "StopSession"}, | ||
| 29 | {0x00130100, nullptr, "GetCupVersion"}, | ||
| 30 | {0x00140100, nullptr, "GetDupAvailability"}, | ||
| 31 | }; | ||
| 32 | |||
| 33 | DLP_CLNT_Interface::DLP_CLNT_Interface() { | ||
| 34 | Register(FunctionTable); | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace DLP | ||
| 38 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h deleted file mode 100644 index 067f11e37..000000000 --- a/src/core/hle/service/dlp/dlp_clnt.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace DLP { | ||
| 11 | |||
| 12 | class DLP_CLNT_Interface final : public Interface { | ||
| 13 | public: | ||
| 14 | DLP_CLNT_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "dlp:CLNT"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace DLP | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp deleted file mode 100644 index fe6be7d32..000000000 --- a/src/core/hle/service/dlp/dlp_fkcl.cpp +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/dlp/dlp_fkcl.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace DLP { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x00010083, nullptr, "Initialize"}, | ||
| 12 | {0x00020000, nullptr, "Finalize"}, | ||
| 13 | {0x00030000, nullptr, "GetEventDesc"}, | ||
| 14 | {0x00040000, nullptr, "GetChannels"}, | ||
| 15 | {0x00050180, nullptr, "StartScan"}, | ||
| 16 | {0x00060000, nullptr, "StopScan"}, | ||
| 17 | {0x00070080, nullptr, "GetServerInfo"}, | ||
| 18 | {0x00080100, nullptr, "GetTitleInfo"}, | ||
| 19 | {0x00090040, nullptr, "GetTitleInfoInOrder"}, | ||
| 20 | {0x000A0080, nullptr, "DeleteScanInfo"}, | ||
| 21 | {0x000B0100, nullptr, "StartFakeSession"}, | ||
| 22 | {0x000C0000, nullptr, "GetMyStatus"}, | ||
| 23 | {0x000D0040, nullptr, "GetConnectingNodes"}, | ||
| 24 | {0x000E0040, nullptr, "GetNodeInfo"}, | ||
| 25 | {0x000F0000, nullptr, "GetWirelessRebootPassphrase"}, | ||
| 26 | {0x00100000, nullptr, "StopSession"}, | ||
| 27 | {0x00110203, nullptr, "Initialize2"}, | ||
| 28 | }; | ||
| 29 | |||
| 30 | DLP_FKCL_Interface::DLP_FKCL_Interface() { | ||
| 31 | Register(FunctionTable); | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace DLP | ||
| 35 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h deleted file mode 100644 index e4837a167..000000000 --- a/src/core/hle/service/dlp/dlp_fkcl.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace DLP { | ||
| 11 | |||
| 12 | class DLP_FKCL_Interface final : public Interface { | ||
| 13 | public: | ||
| 14 | DLP_FKCL_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "dlp:FKCL"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace DLP | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp deleted file mode 100644 index 1bcea43d3..000000000 --- a/src/core/hle/service/dlp/dlp_srvr.cpp +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/hle/ipc.h" | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/dlp/dlp_srvr.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace DLP { | ||
| 13 | |||
| 14 | static void IsChild(Interface* self) { | ||
| 15 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 16 | |||
| 17 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 18 | cmd_buff[2] = 0; | ||
| 19 | |||
| 20 | LOG_WARNING(Service_DLP, "(STUBBED) called"); | ||
| 21 | } | ||
| 22 | |||
| 23 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 24 | {0x00010183, nullptr, "Initialize"}, | ||
| 25 | {0x00020000, nullptr, "Finalize"}, | ||
| 26 | {0x00030000, nullptr, "GetServerState"}, | ||
| 27 | {0x00040000, nullptr, "GetEventDescription"}, | ||
| 28 | {0x00050080, nullptr, "StartAccepting"}, | ||
| 29 | {0x00060000, nullptr, "EndAccepting"}, | ||
| 30 | {0x00070000, nullptr, "StartDistribution"}, | ||
| 31 | {0x000800C0, nullptr, "SendWirelessRebootPassphrase"}, | ||
| 32 | {0x00090040, nullptr, "AcceptClient"}, | ||
| 33 | {0x000A0040, nullptr, "DisconnectClient"}, | ||
| 34 | {0x000B0042, nullptr, "GetConnectingClients"}, | ||
| 35 | {0x000C0040, nullptr, "GetClientInfo"}, | ||
| 36 | {0x000D0040, nullptr, "GetClientState"}, | ||
| 37 | {0x000E0040, IsChild, "IsChild"}, | ||
| 38 | {0x000F0303, nullptr, "InitializeWithName"}, | ||
| 39 | {0x00100000, nullptr, "GetDupNoticeNeed"}, | ||
| 40 | }; | ||
| 41 | |||
| 42 | DLP_SRVR_Interface::DLP_SRVR_Interface() { | ||
| 43 | Register(FunctionTable); | ||
| 44 | } | ||
| 45 | |||
| 46 | } // namespace DLP | ||
| 47 | } // namespace Service | ||
diff --git a/src/core/hle/service/dlp/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h deleted file mode 100644 index 19fe17840..000000000 --- a/src/core/hle/service/dlp/dlp_srvr.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace DLP { | ||
| 11 | |||
| 12 | class DLP_SRVR_Interface final : public Interface { | ||
| 13 | public: | ||
| 14 | DLP_SRVR_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "dlp:SRVR"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace DLP | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp deleted file mode 100644 index 7c8f4339f..000000000 --- a/src/core/hle/service/err_f.cpp +++ /dev/null | |||
| @@ -1,266 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <chrono> | ||
| 7 | #include <iomanip> | ||
| 8 | #include <sstream> | ||
| 9 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/hle/ipc.h" | ||
| 14 | #include "core/hle/result.h" | ||
| 15 | #include "core/hle/service/err_f.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace ERR { | ||
| 19 | |||
| 20 | enum class FatalErrType : u32 { | ||
| 21 | Generic = 0, | ||
| 22 | Corrupted = 1, | ||
| 23 | CardRemoved = 2, | ||
| 24 | Exception = 3, | ||
| 25 | ResultFailure = 4, | ||
| 26 | Logged = 5, | ||
| 27 | }; | ||
| 28 | |||
| 29 | enum class ExceptionType : u32 { | ||
| 30 | PrefetchAbort = 0, | ||
| 31 | DataAbort = 1, | ||
| 32 | Undefined = 2, | ||
| 33 | VectorFP = 3, | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct ExceptionInfo { | ||
| 37 | u8 exception_type; | ||
| 38 | INSERT_PADDING_BYTES(3); | ||
| 39 | u32 sr; | ||
| 40 | u32 ar; | ||
| 41 | u32 fpexc; | ||
| 42 | u32 fpinst; | ||
| 43 | u32 fpinst2; | ||
| 44 | }; | ||
| 45 | static_assert(sizeof(ExceptionInfo) == 0x18, "ExceptionInfo struct has incorrect size"); | ||
| 46 | |||
| 47 | struct ExceptionContext final { | ||
| 48 | std::array<u32, 16> arm_regs; | ||
| 49 | u32 cpsr; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(ExceptionContext) == 0x44, "ExceptionContext struct has incorrect size"); | ||
| 52 | |||
| 53 | struct ExceptionData { | ||
| 54 | ExceptionInfo exception_info; | ||
| 55 | ExceptionContext exception_context; | ||
| 56 | INSERT_PADDING_WORDS(1); | ||
| 57 | }; | ||
| 58 | static_assert(sizeof(ExceptionData) == 0x60, "ExceptionData struct has incorrect size"); | ||
| 59 | |||
| 60 | // This is used instead of ResultCode from result.h | ||
| 61 | // because we can't have non-trivial data members in unions. | ||
| 62 | union RSL { | ||
| 63 | u32 raw; | ||
| 64 | |||
| 65 | BitField<0, 10, u32> description; | ||
| 66 | BitField<10, 8, u32> module; | ||
| 67 | BitField<21, 6, u32> summary; | ||
| 68 | BitField<27, 5, u32> level; | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct ErrInfo { | ||
| 72 | struct ErrInfoCommon { | ||
| 73 | u8 specifier; // 0x0 | ||
| 74 | u8 rev_high; // 0x1 | ||
| 75 | u16 rev_low; // 0x2 | ||
| 76 | RSL result_code; // 0x4 | ||
| 77 | u32 pc_address; // 0x8 | ||
| 78 | u32 pid; // 0xC | ||
| 79 | u32 title_id_low; // 0x10 | ||
| 80 | u32 title_id_high; // 0x14 | ||
| 81 | u32 app_title_id_low; // 0x18 | ||
| 82 | u32 app_title_id_high; // 0x1C | ||
| 83 | } errinfo_common; | ||
| 84 | static_assert(sizeof(ErrInfoCommon) == 0x20, "ErrInfoCommon struct has incorrect size"); | ||
| 85 | |||
| 86 | union { | ||
| 87 | struct { | ||
| 88 | char data[0x60]; // 0x20 | ||
| 89 | } generic; | ||
| 90 | |||
| 91 | struct { | ||
| 92 | ExceptionData exception_data; // 0x20 | ||
| 93 | } exception; | ||
| 94 | |||
| 95 | struct { | ||
| 96 | char message[0x60]; // 0x20 | ||
| 97 | } result_failure; | ||
| 98 | }; | ||
| 99 | }; | ||
| 100 | |||
| 101 | static std::string GetErrType(u8 type_code) { | ||
| 102 | switch (static_cast<FatalErrType>(type_code)) { | ||
| 103 | case FatalErrType::Generic: | ||
| 104 | return "Generic"; | ||
| 105 | case FatalErrType::Corrupted: | ||
| 106 | return "Corrupted"; | ||
| 107 | case FatalErrType::CardRemoved: | ||
| 108 | return "CardRemoved"; | ||
| 109 | case FatalErrType::Exception: | ||
| 110 | return "Exception"; | ||
| 111 | case FatalErrType::ResultFailure: | ||
| 112 | return "ResultFailure"; | ||
| 113 | case FatalErrType::Logged: | ||
| 114 | return "Logged"; | ||
| 115 | default: | ||
| 116 | return "Unknown Error Type"; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static std::string GetExceptionType(u8 type_code) { | ||
| 121 | switch (static_cast<ExceptionType>(type_code)) { | ||
| 122 | case ExceptionType::PrefetchAbort: | ||
| 123 | return "Prefetch Abort"; | ||
| 124 | case ExceptionType::DataAbort: | ||
| 125 | return "Data Abort"; | ||
| 126 | case ExceptionType::Undefined: | ||
| 127 | return "Undefined Exception"; | ||
| 128 | case ExceptionType::VectorFP: | ||
| 129 | return "Vector Floating Point Exception"; | ||
| 130 | default: | ||
| 131 | return "Unknown Exception Type"; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | static std::string GetCurrentSystemTime() { | ||
| 136 | auto now = std::chrono::system_clock::now(); | ||
| 137 | auto time = std::chrono::system_clock::to_time_t(now); | ||
| 138 | |||
| 139 | std::stringstream time_stream; | ||
| 140 | time_stream << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S"); | ||
| 141 | return time_stream.str(); | ||
| 142 | } | ||
| 143 | |||
| 144 | static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) { | ||
| 145 | LOG_CRITICAL(Service_ERR, "PID: 0x%08X", errinfo_common.pid); | ||
| 146 | LOG_CRITICAL(Service_ERR, "REV: 0x%08X_0x%08X", errinfo_common.rev_high, | ||
| 147 | errinfo_common.rev_low); | ||
| 148 | LOG_CRITICAL(Service_ERR, "TID: 0x%08X_0x%08X", errinfo_common.title_id_high, | ||
| 149 | errinfo_common.title_id_low); | ||
| 150 | LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errinfo_common.app_title_id_high, | ||
| 151 | errinfo_common.app_title_id_low); | ||
| 152 | LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errinfo_common.pc_address); | ||
| 153 | |||
| 154 | LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errinfo_common.result_code.raw); | ||
| 155 | LOG_CRITICAL(Service_ERR, " Level: %u", errinfo_common.result_code.level.Value()); | ||
| 156 | LOG_CRITICAL(Service_ERR, " Summary: %u", errinfo_common.result_code.summary.Value()); | ||
| 157 | LOG_CRITICAL(Service_ERR, " Module: %u", errinfo_common.result_code.module.Value()); | ||
| 158 | LOG_CRITICAL(Service_ERR, " Desc: %u", errinfo_common.result_code.description.Value()); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* ThrowFatalError function | ||
| 162 | * Inputs: | ||
| 163 | * 0 : Header code [0x00010800] | ||
| 164 | * 1-32 : FatalErrInfo | ||
| 165 | * Outputs: | ||
| 166 | * 0 : Header code | ||
| 167 | * 1 : Result code | ||
| 168 | */ | ||
| 169 | static void ThrowFatalError(Interface* self) { | ||
| 170 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 171 | |||
| 172 | LOG_CRITICAL(Service_ERR, "Fatal error"); | ||
| 173 | const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); | ||
| 174 | LOG_CRITICAL(Service_ERR, "Fatal error type: %s", | ||
| 175 | GetErrType(errinfo->errinfo_common.specifier).c_str()); | ||
| 176 | Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown); | ||
| 177 | |||
| 178 | // Generic Info | ||
| 179 | LogGenericInfo(errinfo->errinfo_common); | ||
| 180 | |||
| 181 | switch (static_cast<FatalErrType>(errinfo->errinfo_common.specifier)) { | ||
| 182 | case FatalErrType::Generic: | ||
| 183 | case FatalErrType::Corrupted: | ||
| 184 | case FatalErrType::CardRemoved: | ||
| 185 | case FatalErrType::Logged: { | ||
| 186 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | case FatalErrType::Exception: { | ||
| 190 | const auto& errtype = errinfo->exception; | ||
| 191 | |||
| 192 | // Register Info | ||
| 193 | LOG_CRITICAL(Service_ERR, "ARM Registers:"); | ||
| 194 | for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size(); | ||
| 195 | ++index) { | ||
| 196 | if (index < 13) { | ||
| 197 | LOG_DEBUG(Service_ERR, "r%u=0x%08X", index, | ||
| 198 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 199 | } else if (index == 13) { | ||
| 200 | LOG_CRITICAL(Service_ERR, "SP=0x%08X", | ||
| 201 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 202 | } else if (index == 14) { | ||
| 203 | LOG_CRITICAL(Service_ERR, "LR=0x%08X", | ||
| 204 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 205 | } else if (index == 15) { | ||
| 206 | LOG_CRITICAL(Service_ERR, "PC=0x%08X", | ||
| 207 | errtype.exception_data.exception_context.arm_regs.at(index)); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | LOG_CRITICAL(Service_ERR, "CPSR=0x%08X", errtype.exception_data.exception_context.cpsr); | ||
| 211 | |||
| 212 | // Exception Info | ||
| 213 | LOG_CRITICAL( | ||
| 214 | Service_ERR, "EXCEPTION TYPE: %s", | ||
| 215 | GetExceptionType(errtype.exception_data.exception_info.exception_type).c_str()); | ||
| 216 | switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) { | ||
| 217 | case ExceptionType::PrefetchAbort: | ||
| 218 | LOG_CRITICAL(Service_ERR, "IFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||
| 219 | LOG_CRITICAL(Service_ERR, "r15: 0x%08X", errtype.exception_data.exception_info.ar); | ||
| 220 | case ExceptionType::DataAbort: | ||
| 221 | LOG_CRITICAL(Service_ERR, "DFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||
| 222 | LOG_CRITICAL(Service_ERR, "DFAR: 0x%08X", errtype.exception_data.exception_info.ar); | ||
| 223 | break; | ||
| 224 | case ExceptionType::VectorFP: | ||
| 225 | LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", | ||
| 226 | errtype.exception_data.exception_info.fpinst); | ||
| 227 | LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", | ||
| 228 | errtype.exception_data.exception_info.fpinst); | ||
| 229 | LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", | ||
| 230 | errtype.exception_data.exception_info.fpinst2); | ||
| 231 | break; | ||
| 232 | case ExceptionType::Undefined: | ||
| 233 | break; // Not logging exception_info for this case | ||
| 234 | } | ||
| 235 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 239 | case FatalErrType::ResultFailure: { | ||
| 240 | const auto& errtype = errinfo->result_failure; | ||
| 241 | |||
| 242 | // Failure Message | ||
| 243 | LOG_CRITICAL(Service_ERR, "Failure Message: %s", errtype.message); | ||
| 244 | LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | |||
| 248 | } // switch FatalErrType | ||
| 249 | |||
| 250 | cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||
| 251 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 252 | } | ||
| 253 | |||
| 254 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 255 | // clang-format off | ||
| 256 | {0x00010800, ThrowFatalError, "ThrowFatalError"}, | ||
| 257 | {0x00020042, nullptr, "SetUserString"}, | ||
| 258 | // clang-format on | ||
| 259 | }; | ||
| 260 | |||
| 261 | ERR_F::ERR_F() { | ||
| 262 | Register(FunctionTable); | ||
| 263 | } | ||
| 264 | |||
| 265 | } // namespace ERR | ||
| 266 | } // namespace Service | ||
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h deleted file mode 100644 index 5b27fc871..000000000 --- a/src/core/hle/service/err_f.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace ERR { | ||
| 11 | |||
| 12 | class ERR_F final : public Interface { | ||
| 13 | public: | ||
| 14 | ERR_F(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "err:f"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace ERR | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp deleted file mode 100644 index 7ad7798da..000000000 --- a/src/core/hle/service/frd/frd.cpp +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/hle/ipc.h" | ||
| 9 | #include "core/hle/ipc_helpers.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/frd/frd.h" | ||
| 12 | #include "core/hle/service/frd/frd_a.h" | ||
| 13 | #include "core/hle/service/frd/frd_u.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | #include "core/memory.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace FRD { | ||
| 19 | |||
| 20 | static FriendKey my_friend_key = {0, 0, 0ull}; | ||
| 21 | static MyPresence my_presence = {}; | ||
| 22 | |||
| 23 | void GetMyPresence(Service::Interface* self) { | ||
| 24 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 25 | |||
| 26 | u32 shifted_out_size = cmd_buff[64]; | ||
| 27 | u32 my_presence_addr = cmd_buff[65]; | ||
| 28 | |||
| 29 | ASSERT(shifted_out_size == ((sizeof(MyPresence) << 14) | 2)); | ||
| 30 | |||
| 31 | Memory::WriteBlock(my_presence_addr, &my_presence, sizeof(MyPresence)); | ||
| 32 | |||
| 33 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 34 | |||
| 35 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | ||
| 36 | } | ||
| 37 | |||
| 38 | void GetFriendKeyList(Service::Interface* self) { | ||
| 39 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 40 | |||
| 41 | u32 unknown = cmd_buff[1]; | ||
| 42 | u32 frd_count = cmd_buff[2]; | ||
| 43 | u32 frd_key_addr = cmd_buff[65]; | ||
| 44 | |||
| 45 | FriendKey zero_key = {}; | ||
| 46 | for (u32 i = 0; i < frd_count; ++i) { | ||
| 47 | Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey), &zero_key, sizeof(FriendKey)); | ||
| 48 | } | ||
| 49 | |||
| 50 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 51 | cmd_buff[2] = 0; // 0 friends | ||
| 52 | LOG_WARNING(Service_FRD, "(STUBBED) called, unknown=%d, frd_count=%d, frd_key_addr=0x%08X", | ||
| 53 | unknown, frd_count, frd_key_addr); | ||
| 54 | } | ||
| 55 | |||
| 56 | void GetFriendProfile(Service::Interface* self) { | ||
| 57 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 58 | |||
| 59 | u32 count = cmd_buff[1]; | ||
| 60 | u32 frd_key_addr = cmd_buff[3]; | ||
| 61 | u32 profiles_addr = cmd_buff[65]; | ||
| 62 | |||
| 63 | Profile zero_profile = {}; | ||
| 64 | for (u32 i = 0; i < count; ++i) { | ||
| 65 | Memory::WriteBlock(profiles_addr + i * sizeof(Profile), &zero_profile, sizeof(Profile)); | ||
| 66 | } | ||
| 67 | |||
| 68 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 69 | LOG_WARNING(Service_FRD, | ||
| 70 | "(STUBBED) called, count=%d, frd_key_addr=0x%08X, profiles_addr=0x%08X", count, | ||
| 71 | frd_key_addr, profiles_addr); | ||
| 72 | } | ||
| 73 | |||
| 74 | void GetFriendAttributeFlags(Service::Interface* self) { | ||
| 75 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 76 | |||
| 77 | u32 count = cmd_buff[1]; | ||
| 78 | u32 frd_key_addr = cmd_buff[3]; | ||
| 79 | u32 attr_flags_addr = cmd_buff[65]; | ||
| 80 | |||
| 81 | for (u32 i = 0; i < count; ++i) { | ||
| 82 | // TODO:(mailwl) figure out AttributeFlag size and zero all buffer. Assume 1 byte | ||
| 83 | Memory::Write8(attr_flags_addr + i, 0); | ||
| 84 | } | ||
| 85 | |||
| 86 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 87 | LOG_WARNING(Service_FRD, | ||
| 88 | "(STUBBED) called, count=%d, frd_key_addr=0x%08X, attr_flags_addr=0x%08X", count, | ||
| 89 | frd_key_addr, attr_flags_addr); | ||
| 90 | } | ||
| 91 | |||
| 92 | void GetMyFriendKey(Service::Interface* self) { | ||
| 93 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 94 | |||
| 95 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 96 | std::memcpy(&cmd_buff[2], &my_friend_key, sizeof(FriendKey)); | ||
| 97 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | ||
| 98 | } | ||
| 99 | |||
| 100 | void GetMyScreenName(Service::Interface* self) { | ||
| 101 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 102 | |||
| 103 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 104 | // TODO: (mailwl) get the name from config | ||
| 105 | Common::UTF8ToUTF16("Citra").copy(reinterpret_cast<char16_t*>(&cmd_buff[2]), 11); | ||
| 106 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | ||
| 107 | } | ||
| 108 | |||
| 109 | void UnscrambleLocalFriendCode(Service::Interface* self) { | ||
| 110 | const size_t scrambled_friend_code_size = 12; | ||
| 111 | const size_t friend_code_size = 8; | ||
| 112 | |||
| 113 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1C, 1, 2); | ||
| 114 | const u32 friend_code_count = rp.Pop<u32>(); | ||
| 115 | size_t in_buffer_size; | ||
| 116 | const VAddr scrambled_friend_codes = rp.PopStaticBuffer(&in_buffer_size, false); | ||
| 117 | ASSERT_MSG(in_buffer_size == (friend_code_count * scrambled_friend_code_size), | ||
| 118 | "Wrong input buffer size"); | ||
| 119 | |||
| 120 | size_t out_buffer_size; | ||
| 121 | VAddr unscrambled_friend_codes = rp.PeekStaticBuffer(0, &out_buffer_size); | ||
| 122 | ASSERT_MSG(out_buffer_size == (friend_code_count * friend_code_size), | ||
| 123 | "Wrong output buffer size"); | ||
| 124 | |||
| 125 | for (u32 current = 0; current < friend_code_count; ++current) { | ||
| 126 | // TODO(B3N30): Unscramble the codes and compare them against the friend list | ||
| 127 | // Only write 0 if the code isn't in friend list, otherwise write the | ||
| 128 | // unscrambled one | ||
| 129 | // | ||
| 130 | // Code for unscrambling (should be compared to HW): | ||
| 131 | // std::array<u16, 6> scambled_friend_code; | ||
| 132 | // Memory::ReadBlock(scrambled_friend_codes+(current*scrambled_friend_code_size), | ||
| 133 | // scambled_friend_code.data(), scrambled_friend_code_size); std::array<u16, 4> | ||
| 134 | // unscrambled_friend_code; unscrambled_friend_code[0] = scambled_friend_code[0] ^ | ||
| 135 | // scambled_friend_code[5]; unscrambled_friend_code[1] = scambled_friend_code[1] ^ | ||
| 136 | // scambled_friend_code[5]; unscrambled_friend_code[2] = scambled_friend_code[2] ^ | ||
| 137 | // scambled_friend_code[5]; unscrambled_friend_code[3] = scambled_friend_code[3] ^ | ||
| 138 | // scambled_friend_code[5]; | ||
| 139 | |||
| 140 | u64 result = 0ull; | ||
| 141 | Memory::WriteBlock(unscrambled_friend_codes + (current * sizeof(result)), &result, | ||
| 142 | sizeof(result)); | ||
| 143 | } | ||
| 144 | |||
| 145 | LOG_WARNING(Service_FRD, "(STUBBED) called"); | ||
| 146 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 147 | rb.Push(RESULT_SUCCESS); | ||
| 148 | rb.PushStaticBuffer(unscrambled_friend_codes, out_buffer_size, 0); | ||
| 149 | } | ||
| 150 | |||
| 151 | void SetClientSdkVersion(Service::Interface* self) { | ||
| 152 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 153 | |||
| 154 | const u32 version = cmd_buff[1]; | ||
| 155 | |||
| 156 | self->SetVersion(version); | ||
| 157 | |||
| 158 | LOG_WARNING(Service_FRD, "(STUBBED) called, version: 0x%08X", version); | ||
| 159 | |||
| 160 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 161 | } | ||
| 162 | |||
| 163 | void Init() { | ||
| 164 | using namespace Kernel; | ||
| 165 | |||
| 166 | AddService(new FRD_A_Interface); | ||
| 167 | AddService(new FRD_U_Interface); | ||
| 168 | } | ||
| 169 | |||
| 170 | void Shutdown() {} | ||
| 171 | |||
| 172 | } // namespace FRD | ||
| 173 | |||
| 174 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h deleted file mode 100644 index 66a87c8cd..000000000 --- a/src/core/hle/service/frd/frd.h +++ /dev/null | |||
| @@ -1,127 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | |||
| 11 | class Interface; | ||
| 12 | |||
| 13 | namespace FRD { | ||
| 14 | |||
| 15 | struct FriendKey { | ||
| 16 | u32 friend_id; | ||
| 17 | u32 unknown; | ||
| 18 | u64 friend_code; | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct MyPresence { | ||
| 22 | u8 unknown[0x12C]; | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct Profile { | ||
| 26 | u8 region; | ||
| 27 | u8 country; | ||
| 28 | u8 area; | ||
| 29 | u8 language; | ||
| 30 | u32 unknown; | ||
| 31 | }; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * FRD::GetMyPresence service function | ||
| 35 | * Inputs: | ||
| 36 | * 64 : sizeof (MyPresence) << 14 | 2 | ||
| 37 | * 65 : Address of MyPresence structure | ||
| 38 | * Outputs: | ||
| 39 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 40 | */ | ||
| 41 | void GetMyPresence(Service::Interface* self); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * FRD::GetFriendKeyList service function | ||
| 45 | * Inputs: | ||
| 46 | * 1 : Unknown | ||
| 47 | * 2 : Max friends count | ||
| 48 | * 65 : Address of FriendKey List | ||
| 49 | * Outputs: | ||
| 50 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 51 | * 2 : FriendKey count filled | ||
| 52 | */ | ||
| 53 | void GetFriendKeyList(Service::Interface* self); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * FRD::GetFriendProfile service function | ||
| 57 | * Inputs: | ||
| 58 | * 1 : Friends count | ||
| 59 | * 2 : Friends count << 18 | 2 | ||
| 60 | * 3 : Address of FriendKey List | ||
| 61 | * 64 : (count * sizeof (Profile)) << 10 | 2 | ||
| 62 | * 65 : Address of Profiles List | ||
| 63 | * Outputs: | ||
| 64 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 65 | */ | ||
| 66 | void GetFriendProfile(Service::Interface* self); | ||
| 67 | |||
| 68 | /** | ||
| 69 | * FRD::GetFriendAttributeFlags service function | ||
| 70 | * Inputs: | ||
| 71 | * 1 : Friends count | ||
| 72 | * 2 : Friends count << 18 | 2 | ||
| 73 | * 3 : Address of FriendKey List | ||
| 74 | * 65 : Address of AttributeFlags | ||
| 75 | * Outputs: | ||
| 76 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 77 | */ | ||
| 78 | void GetFriendAttributeFlags(Service::Interface* self); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * FRD::GetMyFriendKey service function | ||
| 82 | * Inputs: | ||
| 83 | * none | ||
| 84 | * Outputs: | ||
| 85 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 86 | * 2-5 : FriendKey | ||
| 87 | */ | ||
| 88 | void GetMyFriendKey(Service::Interface* self); | ||
| 89 | |||
| 90 | /** | ||
| 91 | * FRD::GetMyScreenName service function | ||
| 92 | * Outputs: | ||
| 93 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 94 | * 2 : UTF16 encoded name (max 11 symbols) | ||
| 95 | */ | ||
| 96 | void GetMyScreenName(Service::Interface* self); | ||
| 97 | |||
| 98 | /** | ||
| 99 | * FRD::UnscrambleLocalFriendCode service function | ||
| 100 | * Inputs: | ||
| 101 | * 1 : Friend code count | ||
| 102 | * 2 : ((count * 12) << 14) | 0x402 | ||
| 103 | * 3 : Pointer to encoded friend codes. Each is 12 bytes large | ||
| 104 | * 64 : ((count * 8) << 14) | 2 | ||
| 105 | * 65 : Pointer to write decoded local friend codes to. Each is 8 bytes large. | ||
| 106 | * Outputs: | ||
| 107 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 108 | */ | ||
| 109 | void UnscrambleLocalFriendCode(Service::Interface* self); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * FRD::SetClientSdkVersion service function | ||
| 113 | * Inputs: | ||
| 114 | * 1 : Used SDK Version | ||
| 115 | * Outputs: | ||
| 116 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 117 | */ | ||
| 118 | void SetClientSdkVersion(Service::Interface* self); | ||
| 119 | |||
| 120 | /// Initialize FRD service(s) | ||
| 121 | void Init(); | ||
| 122 | |||
| 123 | /// Shutdown FRD service(s) | ||
| 124 | void Shutdown(); | ||
| 125 | |||
| 126 | } // namespace FRD | ||
| 127 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp deleted file mode 100644 index cfc37210b..000000000 --- a/src/core/hle/service/frd/frd_a.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/frd/frd_a.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace FRD { | ||
| 9 | |||
| 10 | // Empty arrays are illegal -- commented out until an entry is added. | ||
| 11 | // const Interface::FunctionInfo FunctionTable[] = { }; | ||
| 12 | |||
| 13 | FRD_A_Interface::FRD_A_Interface() { | ||
| 14 | // Register(FunctionTable); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace FRD | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd_a.h b/src/core/hle/service/frd/frd_a.h deleted file mode 100644 index 006d1cadd..000000000 --- a/src/core/hle/service/frd/frd_a.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace FRD { | ||
| 11 | |||
| 12 | class FRD_A_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | FRD_A_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "frd:a"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace FRD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp deleted file mode 100644 index 6970ff768..000000000 --- a/src/core/hle/service/frd/frd_u.cpp +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/frd/frd.h" | ||
| 6 | #include "core/hle/service/frd/frd_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace FRD { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010000, nullptr, "HasLoggedIn"}, | ||
| 13 | {0x00020000, nullptr, "IsOnline"}, | ||
| 14 | {0x00030000, nullptr, "Login"}, | ||
| 15 | {0x00040000, nullptr, "Logout"}, | ||
| 16 | {0x00050000, GetMyFriendKey, "GetMyFriendKey"}, | ||
| 17 | {0x00060000, nullptr, "GetMyPreference"}, | ||
| 18 | {0x00070000, nullptr, "GetMyProfile"}, | ||
| 19 | {0x00080000, GetMyPresence, "GetMyPresence"}, | ||
| 20 | {0x00090000, GetMyScreenName, "GetMyScreenName"}, | ||
| 21 | {0x000A0000, nullptr, "GetMyMii"}, | ||
| 22 | {0x000B0000, nullptr, "GetMyLocalAccountId"}, | ||
| 23 | {0x000C0000, nullptr, "GetMyPlayingGame"}, | ||
| 24 | {0x000D0000, nullptr, "GetMyFavoriteGame"}, | ||
| 25 | {0x000E0000, nullptr, "GetMyNcPrincipalId"}, | ||
| 26 | {0x000F0000, nullptr, "GetMyComment"}, | ||
| 27 | {0x00100040, nullptr, "GetMyPassword"}, | ||
| 28 | {0x00110080, GetFriendKeyList, "GetFriendKeyList"}, | ||
| 29 | {0x00120042, nullptr, "GetFriendPresence"}, | ||
| 30 | {0x00130142, nullptr, "GetFriendScreenName"}, | ||
| 31 | {0x00140044, nullptr, "GetFriendMii"}, | ||
| 32 | {0x00150042, GetFriendProfile, "GetFriendProfile"}, | ||
| 33 | {0x00160042, nullptr, "GetFriendRelationship"}, | ||
| 34 | {0x00170042, GetFriendAttributeFlags, "GetFriendAttributeFlags"}, | ||
| 35 | {0x00180044, nullptr, "GetFriendPlayingGame"}, | ||
| 36 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, | ||
| 37 | {0x001A00C4, nullptr, "GetFriendInfo"}, | ||
| 38 | {0x001B0080, nullptr, "IsIncludedInFriendList"}, | ||
| 39 | {0x001C0042, UnscrambleLocalFriendCode, "UnscrambleLocalFriendCode"}, | ||
| 40 | {0x001D0002, nullptr, "UpdateGameModeDescription"}, | ||
| 41 | {0x001E02C2, nullptr, "UpdateGameMode"}, | ||
| 42 | {0x001F0042, nullptr, "SendInvitation"}, | ||
| 43 | {0x00200002, nullptr, "AttachToEventNotification"}, | ||
| 44 | {0x00210040, nullptr, "SetNotificationMask"}, | ||
| 45 | {0x00220040, nullptr, "GetEventNotification"}, | ||
| 46 | {0x00230000, nullptr, "GetLastResponseResult"}, | ||
| 47 | {0x00240040, nullptr, "PrincipalIdToFriendCode"}, | ||
| 48 | {0x00250080, nullptr, "FriendCodeToPrincipalId"}, | ||
| 49 | {0x00260080, nullptr, "IsValidFriendCode"}, | ||
| 50 | {0x00270040, nullptr, "ResultToErrorCode"}, | ||
| 51 | {0x00280244, nullptr, "RequestGameAuthentication"}, | ||
| 52 | {0x00290000, nullptr, "GetGameAuthenticationData"}, | ||
| 53 | {0x002A0204, nullptr, "RequestServiceLocator"}, | ||
| 54 | {0x002B0000, nullptr, "GetServiceLocatorData"}, | ||
| 55 | {0x002C0002, nullptr, "DetectNatProperties"}, | ||
| 56 | {0x002D0000, nullptr, "GetNatProperties"}, | ||
| 57 | {0x002E0000, nullptr, "GetServerTimeInterval"}, | ||
| 58 | {0x002F0040, nullptr, "AllowHalfAwake"}, | ||
| 59 | {0x00300000, nullptr, "GetServerTypes"}, | ||
| 60 | {0x00310082, nullptr, "GetFriendComment"}, | ||
| 61 | {0x00320042, SetClientSdkVersion, "SetClientSdkVersion"}, | ||
| 62 | {0x00330000, nullptr, "GetMyApproachContext"}, | ||
| 63 | {0x00340046, nullptr, "AddFriendWithApproach"}, | ||
| 64 | {0x00350082, nullptr, "DecryptApproachContext"}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | FRD_U_Interface::FRD_U_Interface() { | ||
| 68 | Register(FunctionTable); | ||
| 69 | } | ||
| 70 | |||
| 71 | } // namespace FRD | ||
| 72 | } // namespace Service | ||
diff --git a/src/core/hle/service/frd/frd_u.h b/src/core/hle/service/frd/frd_u.h deleted file mode 100644 index 07e43f155..000000000 --- a/src/core/hle/service/frd/frd_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace FRD { | ||
| 11 | |||
| 12 | class FRD_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | FRD_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "frd:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace FRD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp deleted file mode 100644 index b01d6e031..000000000 --- a/src/core/hle/service/http_c.cpp +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/http_c.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace HTTP { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x00010044, nullptr, "Initialize"}, | ||
| 12 | {0x00020082, nullptr, "CreateContext"}, | ||
| 13 | {0x00030040, nullptr, "CloseContext"}, | ||
| 14 | {0x00040040, nullptr, "CancelConnection"}, | ||
| 15 | {0x00050040, nullptr, "GetRequestState"}, | ||
| 16 | {0x00060040, nullptr, "GetDownloadSizeState"}, | ||
| 17 | {0x00070040, nullptr, "GetRequestError"}, | ||
| 18 | {0x00080042, nullptr, "InitializeConnectionSession"}, | ||
| 19 | {0x00090040, nullptr, "BeginRequest"}, | ||
| 20 | {0x000A0040, nullptr, "BeginRequestAsync"}, | ||
| 21 | {0x000B0082, nullptr, "ReceiveData"}, | ||
| 22 | {0x000C0102, nullptr, "ReceiveDataTimeout"}, | ||
| 23 | {0x000D0146, nullptr, "SetProxy"}, | ||
| 24 | {0x000E0040, nullptr, "SetProxyDefault"}, | ||
| 25 | {0x000F00C4, nullptr, "SetBasicAuthorization"}, | ||
| 26 | {0x00100080, nullptr, "SetSocketBufferSize"}, | ||
| 27 | {0x001100C4, nullptr, "AddRequestHeader"}, | ||
| 28 | {0x001200C4, nullptr, "AddPostDataAscii"}, | ||
| 29 | {0x001300C4, nullptr, "AddPostDataBinary"}, | ||
| 30 | {0x00140082, nullptr, "AddPostDataRaw"}, | ||
| 31 | {0x00150080, nullptr, "SetPostDataType"}, | ||
| 32 | {0x001600C4, nullptr, "SendPostDataAscii"}, | ||
| 33 | {0x00170144, nullptr, "SendPostDataAsciiTimeout"}, | ||
| 34 | {0x001800C4, nullptr, "SendPostDataBinary"}, | ||
| 35 | {0x00190144, nullptr, "SendPostDataBinaryTimeout"}, | ||
| 36 | {0x001A0082, nullptr, "SendPostDataRaw"}, | ||
| 37 | {0x001B0102, nullptr, "SendPOSTDataRawTimeout"}, | ||
| 38 | {0x001C0080, nullptr, "SetPostDataEncoding"}, | ||
| 39 | {0x001D0040, nullptr, "NotifyFinishSendPostData"}, | ||
| 40 | {0x001E00C4, nullptr, "GetResponseHeader"}, | ||
| 41 | {0x001F0144, nullptr, "GetResponseHeaderTimeout"}, | ||
| 42 | {0x00200082, nullptr, "GetResponseData"}, | ||
| 43 | {0x00210102, nullptr, "GetResponseDataTimeout"}, | ||
| 44 | {0x00220040, nullptr, "GetResponseStatusCode"}, | ||
| 45 | {0x002300C0, nullptr, "GetResponseStatusCodeTimeout"}, | ||
| 46 | {0x00240082, nullptr, "AddTrustedRootCA"}, | ||
| 47 | {0x00250080, nullptr, "AddDefaultCert"}, | ||
| 48 | {0x00260080, nullptr, "SelectRootCertChain"}, | ||
| 49 | {0x002700C4, nullptr, "SetClientCert"}, | ||
| 50 | {0x002B0080, nullptr, "SetSSLOpt"}, | ||
| 51 | {0x002C0080, nullptr, "SetSSLClearOpt"}, | ||
| 52 | {0x002D0000, nullptr, "CreateRootCertChain"}, | ||
| 53 | {0x002E0040, nullptr, "DestroyRootCertChain"}, | ||
| 54 | {0x002F0082, nullptr, "RootCertChainAddCert"}, | ||
| 55 | {0x00300080, nullptr, "RootCertChainAddDefaultCert"}, | ||
| 56 | {0x00310080, nullptr, "RootCertChainRemoveCert"}, | ||
| 57 | {0x00320084, nullptr, "OpenClientCertContext"}, | ||
| 58 | {0x00330040, nullptr, "OpenDefaultClientCertContext"}, | ||
| 59 | {0x00340040, nullptr, "CloseClientCertContext"}, | ||
| 60 | {0x00350186, nullptr, "SetDefaultProxy"}, | ||
| 61 | {0x00360000, nullptr, "ClearDNSCache"}, | ||
| 62 | {0x00370080, nullptr, "SetKeepAlive"}, | ||
| 63 | {0x003800C0, nullptr, "SetPostDataTypeSize"}, | ||
| 64 | {0x00390000, nullptr, "Finalize"}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | HTTP_C::HTTP_C() { | ||
| 68 | Register(FunctionTable); | ||
| 69 | } | ||
| 70 | |||
| 71 | } // namespace HTTP | ||
| 72 | } // namespace Service | ||
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h deleted file mode 100644 index cff279c02..000000000 --- a/src/core/hle/service/http_c.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace HTTP { | ||
| 11 | |||
| 12 | class HTTP_C final : public Interface { | ||
| 13 | public: | ||
| 14 | HTTP_C(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "http:C"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace HTTP | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/extra_hid.cpp b/src/core/hle/service/ir/extra_hid.cpp deleted file mode 100644 index e7acc17a5..000000000 --- a/src/core/hle/service/ir/extra_hid.cpp +++ /dev/null | |||
| @@ -1,231 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/alignment.h" | ||
| 6 | #include "common/bit_field.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/hle/service/ir/extra_hid.h" | ||
| 10 | #include "core/settings.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | namespace IR { | ||
| 14 | |||
| 15 | enum class RequestID : u8 { | ||
| 16 | /** | ||
| 17 | * ConfigureHIDPolling request | ||
| 18 | * Starts HID input polling, or changes the polling interval if it is already started. | ||
| 19 | * Inputs: | ||
| 20 | * byte 0: request ID | ||
| 21 | * byte 1: polling interval in ms | ||
| 22 | * byte 2: unknown | ||
| 23 | */ | ||
| 24 | ConfigureHIDPolling = 1, | ||
| 25 | |||
| 26 | /** | ||
| 27 | * ReadCalibrationData request | ||
| 28 | * Reads the calibration data stored in circle pad pro. | ||
| 29 | * Inputs: | ||
| 30 | * byte 0: request ID | ||
| 31 | * byte 1: expected response time in ms? | ||
| 32 | * byte 2-3: data offset (aligned to 0x10) | ||
| 33 | * byte 4-5: data size (aligned to 0x10) | ||
| 34 | */ | ||
| 35 | ReadCalibrationData = 2, | ||
| 36 | |||
| 37 | // TODO(wwylele): there are three more request types (id = 3, 4 and 5) | ||
| 38 | }; | ||
| 39 | |||
| 40 | enum class ResponseID : u8 { | ||
| 41 | |||
| 42 | /** | ||
| 43 | * PollHID response | ||
| 44 | * Sends current HID status | ||
| 45 | * Output: | ||
| 46 | * byte 0: response ID | ||
| 47 | * byte 1-3: Right circle pad position. This three bytes are two little-endian 12-bit | ||
| 48 | * fields. The first one is for x-axis and the second one is for y-axis. | ||
| 49 | * byte 4: bit[0:4] battery level; bit[5] ZL button; bit[6] ZR button; bit[7] R button | ||
| 50 | * Note that for the three button fields, the bit is set when the button is NOT pressed. | ||
| 51 | * byte 5: unknown | ||
| 52 | */ | ||
| 53 | PollHID = 0x10, | ||
| 54 | |||
| 55 | /** | ||
| 56 | * ReadCalibrationData response | ||
| 57 | * Sends the calibration data reads from circle pad pro. | ||
| 58 | * Output: | ||
| 59 | * byte 0: resonse ID | ||
| 60 | * byte 1-2: data offset (aligned to 0x10) | ||
| 61 | * byte 3-4: data size (aligned to 0x10) | ||
| 62 | * byte 5-...: calibration data | ||
| 63 | */ | ||
| 64 | ReadCalibrationData = 0x11, | ||
| 65 | }; | ||
| 66 | |||
| 67 | ExtraHID::ExtraHID(SendFunc send_func) : IRDevice(send_func) { | ||
| 68 | LoadInputDevices(); | ||
| 69 | |||
| 70 | // The data below was retrieved from a New 3DS | ||
| 71 | // TODO(wwylele): this data is probably writable (via request 3?) and thus should be saved to | ||
| 72 | // and loaded from somewhere. | ||
| 73 | calibration_data = std::array<u8, 0x40>{{ | ||
| 74 | // 0x00 | ||
| 75 | 0x00, 0x00, 0x08, 0x80, 0x85, 0xEB, 0x11, 0x3F, | ||
| 76 | // 0x08 | ||
| 77 | 0x85, 0xEB, 0x11, 0x3F, 0xFF, 0xFF, 0xFF, 0xF5, | ||
| 78 | // 0x10 | ||
| 79 | 0xFF, 0x00, 0x08, 0x80, 0x85, 0xEB, 0x11, 0x3F, | ||
| 80 | // 0x18 | ||
| 81 | 0x85, 0xEB, 0x11, 0x3F, 0xFF, 0xFF, 0xFF, 0x65, | ||
| 82 | // 0x20 | ||
| 83 | 0xFF, 0x00, 0x08, 0x80, 0x85, 0xEB, 0x11, 0x3F, | ||
| 84 | // 0x28 | ||
| 85 | 0x85, 0xEB, 0x11, 0x3F, 0xFF, 0xFF, 0xFF, 0x65, | ||
| 86 | // 0x30 | ||
| 87 | 0xFF, 0x00, 0x08, 0x80, 0x85, 0xEB, 0x11, 0x3F, | ||
| 88 | // 0x38 | ||
| 89 | 0x85, 0xEB, 0x11, 0x3F, 0xFF, 0xFF, 0xFF, 0x65, | ||
| 90 | }}; | ||
| 91 | |||
| 92 | hid_polling_callback_id = | ||
| 93 | CoreTiming::RegisterEvent("ExtraHID::SendHIDStatus", [this](u64, int cycles_late) { | ||
| 94 | SendHIDStatus(); | ||
| 95 | CoreTiming::ScheduleEvent(msToCycles(hid_period) - cycles_late, | ||
| 96 | hid_polling_callback_id); | ||
| 97 | }); | ||
| 98 | } | ||
| 99 | |||
| 100 | ExtraHID::~ExtraHID() { | ||
| 101 | OnDisconnect(); | ||
| 102 | } | ||
| 103 | |||
| 104 | void ExtraHID::OnConnect() {} | ||
| 105 | |||
| 106 | void ExtraHID::OnDisconnect() { | ||
| 107 | CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0); | ||
| 108 | } | ||
| 109 | |||
| 110 | void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request) { | ||
| 111 | if (request.size() != 3) { | ||
| 112 | LOG_ERROR(Service_IR, "Wrong request size (%zu): %s", request.size(), | ||
| 113 | Common::ArrayToString(request.data(), request.size()).c_str()); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | // Change HID input polling interval | ||
| 118 | CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0); | ||
| 119 | hid_period = request[1]; | ||
| 120 | CoreTiming::ScheduleEvent(msToCycles(hid_period), hid_polling_callback_id); | ||
| 121 | } | ||
| 122 | |||
| 123 | void ExtraHID::HandleReadCalibrationDataRequest(const std::vector<u8>& request_buf) { | ||
| 124 | struct ReadCalibrationDataRequest { | ||
| 125 | RequestID request_id; | ||
| 126 | u8 expected_response_time; | ||
| 127 | u16_le offset; | ||
| 128 | u16_le size; | ||
| 129 | }; | ||
| 130 | static_assert(sizeof(ReadCalibrationDataRequest) == 6, | ||
| 131 | "ReadCalibrationDataRequest has wrong size"); | ||
| 132 | |||
| 133 | if (request_buf.size() != sizeof(ReadCalibrationDataRequest)) { | ||
| 134 | LOG_ERROR(Service_IR, "Wrong request size (%zu): %s", request_buf.size(), | ||
| 135 | Common::ArrayToString(request_buf.data(), request_buf.size()).c_str()); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | ReadCalibrationDataRequest request; | ||
| 140 | std::memcpy(&request, request_buf.data(), sizeof(request)); | ||
| 141 | |||
| 142 | const u16 offset = Common::AlignDown(request.offset, 16); | ||
| 143 | const u16 size = Common::AlignDown(request.size, 16); | ||
| 144 | |||
| 145 | if (offset + size > calibration_data.size()) { | ||
| 146 | LOG_ERROR(Service_IR, "Read beyond the end of calibration data! (offset=%u, size=%u)", | ||
| 147 | offset, size); | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | std::vector<u8> response(5); | ||
| 152 | response[0] = static_cast<u8>(ResponseID::ReadCalibrationData); | ||
| 153 | std::memcpy(&response[1], &request.offset, sizeof(request.offset)); | ||
| 154 | std::memcpy(&response[3], &request.size, sizeof(request.size)); | ||
| 155 | response.insert(response.end(), calibration_data.begin() + offset, | ||
| 156 | calibration_data.begin() + offset + size); | ||
| 157 | Send(response); | ||
| 158 | } | ||
| 159 | |||
| 160 | void ExtraHID::OnReceive(const std::vector<u8>& data) { | ||
| 161 | switch (static_cast<RequestID>(data[0])) { | ||
| 162 | case RequestID::ConfigureHIDPolling: | ||
| 163 | HandleConfigureHIDPollingRequest(data); | ||
| 164 | break; | ||
| 165 | case RequestID::ReadCalibrationData: | ||
| 166 | HandleReadCalibrationDataRequest(data); | ||
| 167 | break; | ||
| 168 | default: | ||
| 169 | LOG_ERROR(Service_IR, "Unknown request: %s", | ||
| 170 | Common::ArrayToString(data.data(), data.size()).c_str()); | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | void ExtraHID::SendHIDStatus() { | ||
| 176 | if (is_device_reload_pending.exchange(false)) | ||
| 177 | LoadInputDevices(); | ||
| 178 | |||
| 179 | struct { | ||
| 180 | union { | ||
| 181 | BitField<0, 8, u32_le> header; | ||
| 182 | BitField<8, 12, u32_le> c_stick_x; | ||
| 183 | BitField<20, 12, u32_le> c_stick_y; | ||
| 184 | } c_stick; | ||
| 185 | union { | ||
| 186 | BitField<0, 5, u8> battery_level; | ||
| 187 | BitField<5, 1, u8> zl_not_held; | ||
| 188 | BitField<6, 1, u8> zr_not_held; | ||
| 189 | BitField<7, 1, u8> r_not_held; | ||
| 190 | } buttons; | ||
| 191 | u8 unknown; | ||
| 192 | } response; | ||
| 193 | static_assert(sizeof(response) == 6, "HID status response has wrong size!"); | ||
| 194 | |||
| 195 | constexpr int C_STICK_CENTER = 0x800; | ||
| 196 | // TODO(wwylele): this value is not accurately measured. We currently assume that the axis can | ||
| 197 | // take values in the whole range of a 12-bit integer. | ||
| 198 | constexpr int C_STICK_RADIUS = 0x7FF; | ||
| 199 | |||
| 200 | float x, y; | ||
| 201 | std::tie(x, y) = c_stick->GetStatus(); | ||
| 202 | |||
| 203 | response.c_stick.header.Assign(static_cast<u8>(ResponseID::PollHID)); | ||
| 204 | response.c_stick.c_stick_x.Assign(static_cast<u32>(C_STICK_CENTER + C_STICK_RADIUS * x)); | ||
| 205 | response.c_stick.c_stick_y.Assign(static_cast<u32>(C_STICK_CENTER + C_STICK_RADIUS * y)); | ||
| 206 | response.buttons.battery_level.Assign(0x1F); | ||
| 207 | response.buttons.zl_not_held.Assign(!zl->GetStatus()); | ||
| 208 | response.buttons.zr_not_held.Assign(!zr->GetStatus()); | ||
| 209 | response.buttons.r_not_held.Assign(1); | ||
| 210 | response.unknown = 0; | ||
| 211 | |||
| 212 | std::vector<u8> response_buffer(sizeof(response)); | ||
| 213 | memcpy(response_buffer.data(), &response, sizeof(response)); | ||
| 214 | Send(response_buffer); | ||
| 215 | } | ||
| 216 | |||
| 217 | void ExtraHID::RequestInputDevicesReload() { | ||
| 218 | is_device_reload_pending.store(true); | ||
| 219 | } | ||
| 220 | |||
| 221 | void ExtraHID::LoadInputDevices() { | ||
| 222 | zl = Input::CreateDevice<Input::ButtonDevice>( | ||
| 223 | Settings::values.buttons[Settings::NativeButton::ZL]); | ||
| 224 | zr = Input::CreateDevice<Input::ButtonDevice>( | ||
| 225 | Settings::values.buttons[Settings::NativeButton::ZR]); | ||
| 226 | c_stick = Input::CreateDevice<Input::AnalogDevice>( | ||
| 227 | Settings::values.analogs[Settings::NativeAnalog::CStick]); | ||
| 228 | } | ||
| 229 | |||
| 230 | } // namespace IR | ||
| 231 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h deleted file mode 100644 index a2459a73a..000000000 --- a/src/core/hle/service/ir/extra_hid.h +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <atomic> | ||
| 9 | #include "core/frontend/input.h" | ||
| 10 | #include "core/hle/service/ir/ir_user.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | namespace IR { | ||
| 14 | |||
| 15 | /** | ||
| 16 | * An IRDevice emulating Circle Pad Pro or New 3DS additional HID hardware. | ||
| 17 | * This device sends periodic udates at a rate configured by the 3DS, and sends calibration data if | ||
| 18 | * requested. | ||
| 19 | */ | ||
| 20 | class ExtraHID final : public IRDevice { | ||
| 21 | public: | ||
| 22 | explicit ExtraHID(SendFunc send_func); | ||
| 23 | ~ExtraHID(); | ||
| 24 | |||
| 25 | void OnConnect() override; | ||
| 26 | void OnDisconnect() override; | ||
| 27 | void OnReceive(const std::vector<u8>& data) override; | ||
| 28 | |||
| 29 | /// Requests input devices reload from current settings. Called when the input settings change. | ||
| 30 | void RequestInputDevicesReload(); | ||
| 31 | |||
| 32 | private: | ||
| 33 | void SendHIDStatus(); | ||
| 34 | void HandleConfigureHIDPollingRequest(const std::vector<u8>& request); | ||
| 35 | void HandleReadCalibrationDataRequest(const std::vector<u8>& request); | ||
| 36 | void LoadInputDevices(); | ||
| 37 | |||
| 38 | u8 hid_period; | ||
| 39 | int hid_polling_callback_id; | ||
| 40 | std::array<u8, 0x40> calibration_data; | ||
| 41 | std::unique_ptr<Input::ButtonDevice> zl; | ||
| 42 | std::unique_ptr<Input::ButtonDevice> zr; | ||
| 43 | std::unique_ptr<Input::AnalogDevice> c_stick; | ||
| 44 | std::atomic<bool> is_device_reload_pending; | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace IR | ||
| 48 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp deleted file mode 100644 index f06dd552f..000000000 --- a/src/core/hle/service/ir/ir.cpp +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ir/ir.h" | ||
| 6 | #include "core/hle/service/ir/ir_rst.h" | ||
| 7 | #include "core/hle/service/ir/ir_u.h" | ||
| 8 | #include "core/hle/service/ir/ir_user.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace IR { | ||
| 13 | |||
| 14 | void Init() { | ||
| 15 | AddService(new IR_RST_Interface); | ||
| 16 | AddService(new IR_U_Interface); | ||
| 17 | AddService(new IR_User_Interface); | ||
| 18 | |||
| 19 | InitUser(); | ||
| 20 | InitRST(); | ||
| 21 | } | ||
| 22 | |||
| 23 | void Shutdown() { | ||
| 24 | ShutdownUser(); | ||
| 25 | ShutdownRST(); | ||
| 26 | } | ||
| 27 | |||
| 28 | void ReloadInputDevices() { | ||
| 29 | ReloadInputDevicesUser(); | ||
| 30 | ReloadInputDevicesRST(); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace IR | ||
| 34 | |||
| 35 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h deleted file mode 100644 index 6be3e950c..000000000 --- a/src/core/hle/service/ir/ir.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | class Interface; | ||
| 10 | |||
| 11 | namespace IR { | ||
| 12 | |||
| 13 | /// Initialize IR service | ||
| 14 | void Init(); | ||
| 15 | |||
| 16 | /// Shutdown IR service | ||
| 17 | void Shutdown(); | ||
| 18 | |||
| 19 | /// Reload input devices. Used when input configuration changed | ||
| 20 | void ReloadInputDevices(); | ||
| 21 | |||
| 22 | } // namespace IR | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp deleted file mode 100644 index 0912d5756..000000000 --- a/src/core/hle/service/ir/ir_rst.cpp +++ /dev/null | |||
| @@ -1,221 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <atomic> | ||
| 6 | #include "common/bit_field.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | #include "core/hle/ipc_helpers.h" | ||
| 10 | #include "core/hle/kernel/event.h" | ||
| 11 | #include "core/hle/kernel/shared_memory.h" | ||
| 12 | #include "core/hle/service/hid/hid.h" | ||
| 13 | #include "core/hle/service/ir/ir.h" | ||
| 14 | #include "core/hle/service/ir/ir_rst.h" | ||
| 15 | #include "core/settings.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace IR { | ||
| 19 | |||
| 20 | union PadState { | ||
| 21 | u32_le hex{}; | ||
| 22 | |||
| 23 | BitField<14, 1, u32_le> zl; | ||
| 24 | BitField<15, 1, u32_le> zr; | ||
| 25 | |||
| 26 | BitField<24, 1, u32_le> c_stick_right; | ||
| 27 | BitField<25, 1, u32_le> c_stick_left; | ||
| 28 | BitField<26, 1, u32_le> c_stick_up; | ||
| 29 | BitField<27, 1, u32_le> c_stick_down; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct PadDataEntry { | ||
| 33 | PadState current_state; | ||
| 34 | PadState delta_additions; | ||
| 35 | PadState delta_removals; | ||
| 36 | |||
| 37 | s16_le c_stick_x; | ||
| 38 | s16_le c_stick_y; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct SharedMem { | ||
| 42 | u64_le index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 | ||
| 43 | u64_le index_reset_ticks_previous; ///< Previous `index_reset_ticks` | ||
| 44 | u32_le index; | ||
| 45 | INSERT_PADDING_WORDS(1); | ||
| 46 | std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries | ||
| 47 | }; | ||
| 48 | |||
| 49 | static_assert(sizeof(SharedMem) == 0x98, "SharedMem has wrong size!"); | ||
| 50 | |||
| 51 | static Kernel::SharedPtr<Kernel::Event> update_event; | ||
| 52 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; | ||
| 53 | static u32 next_pad_index; | ||
| 54 | static int update_callback_id; | ||
| 55 | static std::unique_ptr<Input::ButtonDevice> zl_button; | ||
| 56 | static std::unique_ptr<Input::ButtonDevice> zr_button; | ||
| 57 | static std::unique_ptr<Input::AnalogDevice> c_stick; | ||
| 58 | static std::atomic<bool> is_device_reload_pending; | ||
| 59 | static bool raw_c_stick; | ||
| 60 | static int update_period; | ||
| 61 | |||
| 62 | static void LoadInputDevices() { | ||
| 63 | zl_button = Input::CreateDevice<Input::ButtonDevice>( | ||
| 64 | Settings::values.buttons[Settings::NativeButton::ZL]); | ||
| 65 | zr_button = Input::CreateDevice<Input::ButtonDevice>( | ||
| 66 | Settings::values.buttons[Settings::NativeButton::ZR]); | ||
| 67 | c_stick = Input::CreateDevice<Input::AnalogDevice>( | ||
| 68 | Settings::values.analogs[Settings::NativeAnalog::CStick]); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void UnloadInputDevices() { | ||
| 72 | zl_button = nullptr; | ||
| 73 | zr_button = nullptr; | ||
| 74 | c_stick = nullptr; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void UpdateCallback(u64 userdata, int cycles_late) { | ||
| 78 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_memory->GetPointer()); | ||
| 79 | |||
| 80 | if (is_device_reload_pending.exchange(false)) | ||
| 81 | LoadInputDevices(); | ||
| 82 | |||
| 83 | PadState state; | ||
| 84 | state.zl.Assign(zl_button->GetStatus()); | ||
| 85 | state.zr.Assign(zr_button->GetStatus()); | ||
| 86 | |||
| 87 | // Get current c-stick position and update c-stick direction | ||
| 88 | float c_stick_x_f, c_stick_y_f; | ||
| 89 | std::tie(c_stick_x_f, c_stick_y_f) = c_stick->GetStatus(); | ||
| 90 | constexpr int MAX_CSTICK_RADIUS = 0x9C; // Max value for a c-stick radius | ||
| 91 | const s16 c_stick_x = static_cast<s16>(c_stick_x_f * MAX_CSTICK_RADIUS); | ||
| 92 | const s16 c_stick_y = static_cast<s16>(c_stick_y_f * MAX_CSTICK_RADIUS); | ||
| 93 | |||
| 94 | if (!raw_c_stick) { | ||
| 95 | const HID::DirectionState direction = HID::GetStickDirectionState(c_stick_x, c_stick_y); | ||
| 96 | state.c_stick_up.Assign(direction.up); | ||
| 97 | state.c_stick_down.Assign(direction.down); | ||
| 98 | state.c_stick_left.Assign(direction.left); | ||
| 99 | state.c_stick_right.Assign(direction.right); | ||
| 100 | } | ||
| 101 | |||
| 102 | // TODO (wwylele): implement raw C-stick data for raw_c_stick = true | ||
| 103 | |||
| 104 | const u32 last_entry_index = mem->index; | ||
| 105 | mem->index = next_pad_index; | ||
| 106 | next_pad_index = (next_pad_index + 1) % mem->entries.size(); | ||
| 107 | |||
| 108 | // Get the previous Pad state | ||
| 109 | PadState old_state{mem->entries[last_entry_index].current_state}; | ||
| 110 | |||
| 111 | // Compute bitmask with 1s for bits different from the old state | ||
| 112 | PadState changed = {state.hex ^ old_state.hex}; | ||
| 113 | |||
| 114 | // Get the current Pad entry | ||
| 115 | PadDataEntry& pad_entry = mem->entries[mem->index]; | ||
| 116 | |||
| 117 | // Update entry properties | ||
| 118 | pad_entry.current_state.hex = state.hex; | ||
| 119 | pad_entry.delta_additions.hex = changed.hex & state.hex; | ||
| 120 | pad_entry.delta_removals.hex = changed.hex & old_state.hex; | ||
| 121 | pad_entry.c_stick_x = c_stick_x; | ||
| 122 | pad_entry.c_stick_y = c_stick_y; | ||
| 123 | |||
| 124 | // If we just updated index 0, provide a new timestamp | ||
| 125 | if (mem->index == 0) { | ||
| 126 | mem->index_reset_ticks_previous = mem->index_reset_ticks; | ||
| 127 | mem->index_reset_ticks = CoreTiming::GetTicks(); | ||
| 128 | } | ||
| 129 | |||
| 130 | update_event->Signal(); | ||
| 131 | |||
| 132 | // Reschedule recurrent event | ||
| 133 | CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | ||
| 137 | * IR::GetHandles service function | ||
| 138 | * Outputs: | ||
| 139 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 140 | * 2 : Translate header, used by the ARM11-kernel | ||
| 141 | * 3 : Shared memory handle | ||
| 142 | * 4 : Event handle | ||
| 143 | */ | ||
| 144 | static void GetHandles(Interface* self) { | ||
| 145 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 0, 0); | ||
| 146 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); | ||
| 147 | rb.Push(RESULT_SUCCESS); | ||
| 148 | rb.PushMoveHandles(Kernel::g_handle_table.Create(Service::IR::shared_memory).Unwrap(), | ||
| 149 | Kernel::g_handle_table.Create(Service::IR::update_event).Unwrap()); | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * IR::Initialize service function | ||
| 154 | * Inputs: | ||
| 155 | * 1 : pad state update period in ms | ||
| 156 | * 2 : bool output raw c-stick data | ||
| 157 | */ | ||
| 158 | static void Initialize(Interface* self) { | ||
| 159 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 0); | ||
| 160 | update_period = static_cast<int>(rp.Pop<u32>()); | ||
| 161 | raw_c_stick = rp.Pop<bool>(); | ||
| 162 | |||
| 163 | if (raw_c_stick) | ||
| 164 | LOG_ERROR(Service_IR, "raw C-stick data is not implemented!"); | ||
| 165 | |||
| 166 | next_pad_index = 0; | ||
| 167 | is_device_reload_pending.store(true); | ||
| 168 | CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id); | ||
| 169 | |||
| 170 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 171 | rb.Push(RESULT_SUCCESS); | ||
| 172 | |||
| 173 | LOG_DEBUG(Service_IR, "called. update_period=%d, raw_c_stick=%d", update_period, raw_c_stick); | ||
| 174 | } | ||
| 175 | |||
| 176 | static void Shutdown(Interface* self) { | ||
| 177 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); | ||
| 178 | |||
| 179 | CoreTiming::UnscheduleEvent(update_callback_id, 0); | ||
| 180 | UnloadInputDevices(); | ||
| 181 | |||
| 182 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 183 | rb.Push(RESULT_SUCCESS); | ||
| 184 | LOG_DEBUG(Service_IR, "called"); | ||
| 185 | } | ||
| 186 | |||
| 187 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 188 | {0x00010000, GetHandles, "GetHandles"}, | ||
| 189 | {0x00020080, Initialize, "Initialize"}, | ||
| 190 | {0x00030000, Shutdown, "Shutdown"}, | ||
| 191 | {0x00090000, nullptr, "WriteToTwoFields"}, | ||
| 192 | }; | ||
| 193 | |||
| 194 | IR_RST_Interface::IR_RST_Interface() { | ||
| 195 | Register(FunctionTable); | ||
| 196 | } | ||
| 197 | |||
| 198 | void InitRST() { | ||
| 199 | using namespace Kernel; | ||
| 200 | // Note: these two kernel objects are even available before Initialize service function is | ||
| 201 | // called. | ||
| 202 | shared_memory = | ||
| 203 | SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, | ||
| 204 | 0, MemoryRegion::BASE, "IRRST:SharedMemory"); | ||
| 205 | update_event = Event::Create(ResetType::OneShot, "IRRST:UpdateEvent"); | ||
| 206 | |||
| 207 | update_callback_id = CoreTiming::RegisterEvent("IRRST:UpdateCallBack", UpdateCallback); | ||
| 208 | } | ||
| 209 | |||
| 210 | void ShutdownRST() { | ||
| 211 | shared_memory = nullptr; | ||
| 212 | update_event = nullptr; | ||
| 213 | UnloadInputDevices(); | ||
| 214 | } | ||
| 215 | |||
| 216 | void ReloadInputDevicesRST() { | ||
| 217 | is_device_reload_pending.store(true); | ||
| 218 | } | ||
| 219 | |||
| 220 | } // namespace IR | ||
| 221 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h deleted file mode 100644 index d932bb7e5..000000000 --- a/src/core/hle/service/ir/ir_rst.h +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace IR { | ||
| 11 | |||
| 12 | class IR_RST_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | IR_RST_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ir:rst"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | void InitRST(); | ||
| 22 | void ShutdownRST(); | ||
| 23 | |||
| 24 | /// Reload input devices. Used when input configuration changed | ||
| 25 | void ReloadInputDevicesRST(); | ||
| 26 | |||
| 27 | } // namespace IR | ||
| 28 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp deleted file mode 100644 index ce00d5732..000000000 --- a/src/core/hle/service/ir/ir_u.cpp +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ir/ir_u.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace IR { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | {0x00010000, nullptr, "Initialize"}, | ||
| 13 | {0x00020000, nullptr, "Shutdown"}, | ||
| 14 | {0x00030042, nullptr, "StartSendTransfer"}, | ||
| 15 | {0x00040000, nullptr, "WaitSendTransfer"}, | ||
| 16 | {0x000500C2, nullptr, "StartRecvTransfer"}, | ||
| 17 | {0x00060000, nullptr, "WaitRecvTransfer"}, | ||
| 18 | {0x00070080, nullptr, "GetRecvTransferCount"}, | ||
| 19 | {0x00080000, nullptr, "GetSendState"}, | ||
| 20 | {0x00090040, nullptr, "SetBitRate"}, | ||
| 21 | {0x000A0000, nullptr, "GetBitRate"}, | ||
| 22 | {0x000B0040, nullptr, "SetIRLEDState"}, | ||
| 23 | {0x000C0000, nullptr, "GetIRLEDRecvState"}, | ||
| 24 | {0x000D0000, nullptr, "GetSendFinishedEvent"}, | ||
| 25 | {0x000E0000, nullptr, "GetRecvFinishedEvent"}, | ||
| 26 | {0x000F0000, nullptr, "GetTransferState"}, | ||
| 27 | {0x00100000, nullptr, "GetErrorStatus"}, | ||
| 28 | {0x00110040, nullptr, "SetSleepModeActive"}, | ||
| 29 | {0x00120040, nullptr, "SetSleepModeState"}, | ||
| 30 | // clang-format on | ||
| 31 | }; | ||
| 32 | |||
| 33 | IR_U_Interface::IR_U_Interface() { | ||
| 34 | Register(FunctionTable); | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace IR | ||
| 38 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h deleted file mode 100644 index 056d2ce1a..000000000 --- a/src/core/hle/service/ir/ir_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace IR { | ||
| 11 | |||
| 12 | class IR_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | IR_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ir:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace IR | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp deleted file mode 100644 index fbdf7a465..000000000 --- a/src/core/hle/service/ir/ir_user.cpp +++ /dev/null | |||
| @@ -1,558 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <boost/crc.hpp> | ||
| 7 | #include <boost/optional.hpp> | ||
| 8 | #include "common/string_util.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/ipc_helpers.h" | ||
| 11 | #include "core/hle/kernel/event.h" | ||
| 12 | #include "core/hle/kernel/shared_memory.h" | ||
| 13 | #include "core/hle/service/ir/extra_hid.h" | ||
| 14 | #include "core/hle/service/ir/ir.h" | ||
| 15 | #include "core/hle/service/ir/ir_user.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace IR { | ||
| 19 | |||
| 20 | // This is a header that will present in the ir:USER shared memory if it is initialized with | ||
| 21 | // InitializeIrNopShared service function. Otherwise the shared memory doesn't have this header if | ||
| 22 | // it is initialized with InitializeIrNop service function. | ||
| 23 | struct SharedMemoryHeader { | ||
| 24 | u32_le latest_receive_error_result; | ||
| 25 | u32_le latest_send_error_result; | ||
| 26 | // TODO(wwylele): for these fields below, make them enum when the meaning of values is known. | ||
| 27 | u8 connection_status; | ||
| 28 | u8 trying_to_connect_status; | ||
| 29 | u8 connection_role; | ||
| 30 | u8 machine_id; | ||
| 31 | u8 connected; | ||
| 32 | u8 network_id; | ||
| 33 | u8 initialized; | ||
| 34 | u8 unknown; | ||
| 35 | |||
| 36 | // This is not the end of the shared memory. It is followed by a receive buffer and a send | ||
| 37 | // buffer. We handle receive buffer in the BufferManager class. For the send buffer, because | ||
| 38 | // games usually don't access it, we don't emulate it. | ||
| 39 | }; | ||
| 40 | static_assert(sizeof(SharedMemoryHeader) == 16, "SharedMemoryHeader has wrong size!"); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * A manager of the send/receive buffers in the shared memory. Currently it is only used for the | ||
| 44 | * receive buffer. | ||
| 45 | * | ||
| 46 | * A buffer consists of three parts: | ||
| 47 | * - BufferInfo: stores available count of packets, and their position in the PacketInfo | ||
| 48 | * circular queue. | ||
| 49 | * - PacketInfo circular queue: stores the position of each avaiable packets in the Packet data | ||
| 50 | * buffer. Each entry is a pair of {offset, size}. | ||
| 51 | * - Packet data circular buffer: stores the actual data of packets. | ||
| 52 | * | ||
| 53 | * IR packets can be put into and get from the buffer. | ||
| 54 | * | ||
| 55 | * When a new packet is put into the buffer, its data is put into the data circular buffer, | ||
| 56 | * following the end of previous packet data. A new entry is also added to the PacketInfo circular | ||
| 57 | * queue pointing to the added packet data. Then BufferInfo is updated. | ||
| 58 | * | ||
| 59 | * Packets can be released from the other end of the buffer. When releasing a packet, the front | ||
| 60 | * entry in thePacketInfo circular queue is removed, and as a result the corresponding memory in the | ||
| 61 | * data circular buffer is also released. BufferInfo is updated as well. | ||
| 62 | * | ||
| 63 | * The client application usually has a similar manager constructed over the same shared memory | ||
| 64 | * region, performing the same put/get/release operation. This way the client and the service | ||
| 65 | * communicate via a pair of manager of the same buffer. | ||
| 66 | * | ||
| 67 | * TODO(wwylele): implement Get function, which is used by ReceiveIrnop service function. | ||
| 68 | */ | ||
| 69 | class BufferManager { | ||
| 70 | public: | ||
| 71 | BufferManager(Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_, u32 info_offset_, | ||
| 72 | u32 buffer_offset_, u32 max_packet_count_, u32 buffer_size) | ||
| 73 | : shared_memory(shared_memory_), info_offset(info_offset_), buffer_offset(buffer_offset_), | ||
| 74 | max_packet_count(max_packet_count_), | ||
| 75 | max_data_size(buffer_size - sizeof(PacketInfo) * max_packet_count_) { | ||
| 76 | UpdateBufferInfo(); | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Puts a packet to the head of the buffer. | ||
| 81 | * @params packet The data of the packet to put. | ||
| 82 | * @returns whether the operation is successful. | ||
| 83 | */ | ||
| 84 | bool Put(const std::vector<u8>& packet) { | ||
| 85 | if (info.packet_count == max_packet_count) | ||
| 86 | return false; | ||
| 87 | |||
| 88 | u32 write_offset; | ||
| 89 | |||
| 90 | // finds free space offset in data buffer | ||
| 91 | if (info.packet_count == 0) { | ||
| 92 | write_offset = 0; | ||
| 93 | if (packet.size() > max_data_size) | ||
| 94 | return false; | ||
| 95 | } else { | ||
| 96 | const u32 last_index = (info.end_index + max_packet_count - 1) % max_packet_count; | ||
| 97 | const PacketInfo first = GetPacketInfo(info.begin_index); | ||
| 98 | const PacketInfo last = GetPacketInfo(last_index); | ||
| 99 | write_offset = (last.offset + last.size) % max_data_size; | ||
| 100 | const u32 free_space = (first.offset + max_data_size - write_offset) % max_data_size; | ||
| 101 | if (packet.size() > free_space) | ||
| 102 | return false; | ||
| 103 | } | ||
| 104 | |||
| 105 | // writes packet info | ||
| 106 | PacketInfo packet_info{write_offset, static_cast<u32>(packet.size())}; | ||
| 107 | SetPacketInfo(info.end_index, packet_info); | ||
| 108 | |||
| 109 | // writes packet data | ||
| 110 | for (size_t i = 0; i < packet.size(); ++i) { | ||
| 111 | *GetDataBufferPointer((write_offset + i) % max_data_size) = packet[i]; | ||
| 112 | } | ||
| 113 | |||
| 114 | // updates buffer info | ||
| 115 | info.end_index++; | ||
| 116 | info.end_index %= max_packet_count; | ||
| 117 | info.packet_count++; | ||
| 118 | UpdateBufferInfo(); | ||
| 119 | return true; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Release packets from the tail of the buffer | ||
| 124 | * @params count Numbers of packets to release. | ||
| 125 | * @returns whether the operation is successful. | ||
| 126 | */ | ||
| 127 | bool Release(u32 count) { | ||
| 128 | if (info.packet_count < count) | ||
| 129 | return false; | ||
| 130 | |||
| 131 | info.packet_count -= count; | ||
| 132 | info.begin_index += count; | ||
| 133 | info.begin_index %= max_packet_count; | ||
| 134 | UpdateBufferInfo(); | ||
| 135 | return true; | ||
| 136 | } | ||
| 137 | |||
| 138 | private: | ||
| 139 | struct BufferInfo { | ||
| 140 | u32_le begin_index; | ||
| 141 | u32_le end_index; | ||
| 142 | u32_le packet_count; | ||
| 143 | u32_le unknown; | ||
| 144 | }; | ||
| 145 | static_assert(sizeof(BufferInfo) == 16, "BufferInfo has wrong size!"); | ||
| 146 | |||
| 147 | struct PacketInfo { | ||
| 148 | u32_le offset; | ||
| 149 | u32_le size; | ||
| 150 | }; | ||
| 151 | static_assert(sizeof(PacketInfo) == 8, "PacketInfo has wrong size!"); | ||
| 152 | |||
| 153 | u8* GetPacketInfoPointer(u32 index) { | ||
| 154 | return shared_memory->GetPointer(buffer_offset + sizeof(PacketInfo) * index); | ||
| 155 | } | ||
| 156 | |||
| 157 | void SetPacketInfo(u32 index, const PacketInfo& packet_info) { | ||
| 158 | memcpy(GetPacketInfoPointer(index), &packet_info, sizeof(PacketInfo)); | ||
| 159 | } | ||
| 160 | |||
| 161 | PacketInfo GetPacketInfo(u32 index) { | ||
| 162 | PacketInfo packet_info; | ||
| 163 | memcpy(&packet_info, GetPacketInfoPointer(index), sizeof(PacketInfo)); | ||
| 164 | return packet_info; | ||
| 165 | } | ||
| 166 | |||
| 167 | u8* GetDataBufferPointer(u32 offset) { | ||
| 168 | return shared_memory->GetPointer(buffer_offset + sizeof(PacketInfo) * max_packet_count + | ||
| 169 | offset); | ||
| 170 | } | ||
| 171 | |||
| 172 | void UpdateBufferInfo() { | ||
| 173 | if (info_offset) { | ||
| 174 | memcpy(shared_memory->GetPointer(info_offset), &info, sizeof(info)); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | BufferInfo info{0, 0, 0, 0}; | ||
| 179 | Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; | ||
| 180 | u32 info_offset; | ||
| 181 | u32 buffer_offset; | ||
| 182 | u32 max_packet_count; | ||
| 183 | u32 max_data_size; | ||
| 184 | }; | ||
| 185 | |||
| 186 | static Kernel::SharedPtr<Kernel::Event> conn_status_event, send_event, receive_event; | ||
| 187 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; | ||
| 188 | static std::unique_ptr<ExtraHID> extra_hid; | ||
| 189 | static IRDevice* connected_device; | ||
| 190 | static boost::optional<BufferManager> receive_buffer; | ||
| 191 | |||
| 192 | /// Wraps the payload into packet and puts it to the receive buffer | ||
| 193 | static void PutToReceive(const std::vector<u8>& payload) { | ||
| 194 | LOG_TRACE(Service_IR, "called, data=%s", | ||
| 195 | Common::ArrayToString(payload.data(), payload.size()).c_str()); | ||
| 196 | size_t size = payload.size(); | ||
| 197 | |||
| 198 | std::vector<u8> packet; | ||
| 199 | |||
| 200 | // Builds packet header. For the format info: | ||
| 201 | // https://www.3dbrew.org/wiki/IRUSER_Shared_Memory#Packet_structure | ||
| 202 | |||
| 203 | // fixed value | ||
| 204 | packet.push_back(0xA5); | ||
| 205 | // destination network ID | ||
| 206 | u8 network_id = *(shared_memory->GetPointer(offsetof(SharedMemoryHeader, network_id))); | ||
| 207 | packet.push_back(network_id); | ||
| 208 | |||
| 209 | // puts the size info. | ||
| 210 | // The highest bit of the first byte is unknown, which is set to zero here. The second highest | ||
| 211 | // bit is a flag that determines whether the size info is in extended form. If the packet size | ||
| 212 | // can be represent within 6 bits, the short form (1 byte) of size info is chosen, the size is | ||
| 213 | // put to the lower bits of this byte, and the flag is clear. If the packet size cannot be | ||
| 214 | // represent within 6 bits, the extended form (2 bytes) is chosen, the lower 8 bits of the size | ||
| 215 | // is put to the second byte, the higher bits of the size is put to the lower bits of the first | ||
| 216 | // byte, and the flag is set. Note that the packet size must be within 14 bits due to this | ||
| 217 | // format restriction, or it will overlap with the flag bit. | ||
| 218 | if (size < 0x40) { | ||
| 219 | packet.push_back(static_cast<u8>(size)); | ||
| 220 | } else if (size < 0x4000) { | ||
| 221 | packet.push_back(static_cast<u8>(size >> 8) | 0x40); | ||
| 222 | packet.push_back(static_cast<u8>(size)); | ||
| 223 | } else { | ||
| 224 | ASSERT(false); | ||
| 225 | } | ||
| 226 | |||
| 227 | // puts the payload | ||
| 228 | packet.insert(packet.end(), payload.begin(), payload.end()); | ||
| 229 | |||
| 230 | // calculates CRC and puts to the end | ||
| 231 | packet.push_back(boost::crc<8, 0x07, 0, 0, false, false>(packet.data(), packet.size())); | ||
| 232 | |||
| 233 | if (receive_buffer->Put(packet)) { | ||
| 234 | receive_event->Signal(); | ||
| 235 | } else { | ||
| 236 | LOG_ERROR(Service_IR, "receive buffer is full!"); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * IR::InitializeIrNopShared service function | ||
| 242 | * Initializes ir:USER service with a user provided shared memory. The shared memory is configured | ||
| 243 | * to shared mode (with SharedMemoryHeader at the beginning of the shared memory). | ||
| 244 | * Inputs: | ||
| 245 | * 1 : Size of shared memory | ||
| 246 | * 2 : Recv buffer size | ||
| 247 | * 3 : Recv buffer packet count | ||
| 248 | * 4 : Send buffer size | ||
| 249 | * 5 : Send buffer packet count | ||
| 250 | * 6 : BaudRate (u8) | ||
| 251 | * 7 : 0 (Handle descriptor) | ||
| 252 | * 8 : Handle of shared memory | ||
| 253 | * Outputs: | ||
| 254 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 255 | */ | ||
| 256 | static void InitializeIrNopShared(Interface* self) { | ||
| 257 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 6, 2); | ||
| 258 | const u32 shared_buff_size = rp.Pop<u32>(); | ||
| 259 | const u32 recv_buff_size = rp.Pop<u32>(); | ||
| 260 | const u32 recv_buff_packet_count = rp.Pop<u32>(); | ||
| 261 | const u32 send_buff_size = rp.Pop<u32>(); | ||
| 262 | const u32 send_buff_packet_count = rp.Pop<u32>(); | ||
| 263 | const u8 baud_rate = rp.Pop<u8>(); | ||
| 264 | const Kernel::Handle handle = rp.PopHandle(); | ||
| 265 | |||
| 266 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 267 | |||
| 268 | shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle); | ||
| 269 | if (!shared_memory) { | ||
| 270 | LOG_CRITICAL(Service_IR, "invalid shared memory handle 0x%08X", handle); | ||
| 271 | rb.Push(IPC::ERR_INVALID_HANDLE); | ||
| 272 | return; | ||
| 273 | } | ||
| 274 | shared_memory->name = "IR_USER: shared memory"; | ||
| 275 | |||
| 276 | receive_buffer = | ||
| 277 | BufferManager(shared_memory, 0x10, 0x20, recv_buff_packet_count, recv_buff_size); | ||
| 278 | SharedMemoryHeader shared_memory_init{}; | ||
| 279 | shared_memory_init.initialized = 1; | ||
| 280 | std::memcpy(shared_memory->GetPointer(), &shared_memory_init, sizeof(SharedMemoryHeader)); | ||
| 281 | |||
| 282 | rb.Push(RESULT_SUCCESS); | ||
| 283 | |||
| 284 | LOG_INFO(Service_IR, "called, shared_buff_size=%u, recv_buff_size=%u, " | ||
| 285 | "recv_buff_packet_count=%u, send_buff_size=%u, " | ||
| 286 | "send_buff_packet_count=%u, baud_rate=%u, handle=0x%08X", | ||
| 287 | shared_buff_size, recv_buff_size, recv_buff_packet_count, send_buff_size, | ||
| 288 | send_buff_packet_count, baud_rate, handle); | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * IR::RequireConnection service function | ||
| 293 | * Searches for an IR device and connects to it. After connecting to the device, applications can | ||
| 294 | * use SendIrNop function, ReceiveIrNop function (or read from the buffer directly) to communicate | ||
| 295 | * with the device. | ||
| 296 | * Inputs: | ||
| 297 | * 1 : device ID? always 1 for circle pad pro | ||
| 298 | * Outputs: | ||
| 299 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 300 | */ | ||
| 301 | static void RequireConnection(Interface* self) { | ||
| 302 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0); | ||
| 303 | const u8 device_id = rp.Pop<u8>(); | ||
| 304 | |||
| 305 | u8* shared_memory_ptr = shared_memory->GetPointer(); | ||
| 306 | if (device_id == 1) { | ||
| 307 | // These values are observed on a New 3DS. The meaning of them is unclear. | ||
| 308 | // TODO (wwylele): should assign network_id a (random?) number | ||
| 309 | shared_memory_ptr[offsetof(SharedMemoryHeader, connection_status)] = 2; | ||
| 310 | shared_memory_ptr[offsetof(SharedMemoryHeader, connection_role)] = 2; | ||
| 311 | shared_memory_ptr[offsetof(SharedMemoryHeader, connected)] = 1; | ||
| 312 | |||
| 313 | connected_device = extra_hid.get(); | ||
| 314 | connected_device->OnConnect(); | ||
| 315 | conn_status_event->Signal(); | ||
| 316 | } else { | ||
| 317 | LOG_WARNING(Service_IR, "unknown device id %u. Won't connect.", device_id); | ||
| 318 | shared_memory_ptr[offsetof(SharedMemoryHeader, connection_status)] = 1; | ||
| 319 | shared_memory_ptr[offsetof(SharedMemoryHeader, trying_to_connect_status)] = 2; | ||
| 320 | } | ||
| 321 | |||
| 322 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 323 | rb.Push(RESULT_SUCCESS); | ||
| 324 | |||
| 325 | LOG_INFO(Service_IR, "called, device_id = %u", device_id); | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * IR::GetReceiveEvent service function | ||
| 330 | * Gets an event that is signaled when a packet is received from the IR device. | ||
| 331 | * Outputs: | ||
| 332 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 333 | * 2 : 0 (Handle descriptor) | ||
| 334 | * 3 : Receive event handle | ||
| 335 | */ | ||
| 336 | void GetReceiveEvent(Interface* self) { | ||
| 337 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0A, 1, 2); | ||
| 338 | |||
| 339 | rb.Push(RESULT_SUCCESS); | ||
| 340 | rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::receive_event).Unwrap()); | ||
| 341 | |||
| 342 | LOG_INFO(Service_IR, "called"); | ||
| 343 | } | ||
| 344 | |||
| 345 | /** | ||
| 346 | * IR::GetSendEvent service function | ||
| 347 | * Gets an event that is signaled when the sending of a packet is complete | ||
| 348 | * Outputs: | ||
| 349 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 350 | * 2 : 0 (Handle descriptor) | ||
| 351 | * 3 : Send event handle | ||
| 352 | */ | ||
| 353 | void GetSendEvent(Interface* self) { | ||
| 354 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0B, 1, 2); | ||
| 355 | |||
| 356 | rb.Push(RESULT_SUCCESS); | ||
| 357 | rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::send_event).Unwrap()); | ||
| 358 | |||
| 359 | LOG_INFO(Service_IR, "called"); | ||
| 360 | } | ||
| 361 | |||
| 362 | /** | ||
| 363 | * IR::Disconnect service function | ||
| 364 | * Disconnects from the current connected IR device. | ||
| 365 | * Outputs: | ||
| 366 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 367 | */ | ||
| 368 | static void Disconnect(Interface* self) { | ||
| 369 | if (connected_device) { | ||
| 370 | connected_device->OnDisconnect(); | ||
| 371 | connected_device = nullptr; | ||
| 372 | conn_status_event->Signal(); | ||
| 373 | } | ||
| 374 | |||
| 375 | u8* shared_memory_ptr = shared_memory->GetPointer(); | ||
| 376 | shared_memory_ptr[offsetof(SharedMemoryHeader, connection_status)] = 0; | ||
| 377 | shared_memory_ptr[offsetof(SharedMemoryHeader, connected)] = 0; | ||
| 378 | |||
| 379 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x09, 1, 0); | ||
| 380 | rb.Push(RESULT_SUCCESS); | ||
| 381 | |||
| 382 | LOG_INFO(Service_IR, "called"); | ||
| 383 | } | ||
| 384 | |||
| 385 | /** | ||
| 386 | * IR::GetConnectionStatusEvent service function | ||
| 387 | * Gets an event that is signaled when the connection status is changed | ||
| 388 | * Outputs: | ||
| 389 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 390 | * 2 : 0 (Handle descriptor) | ||
| 391 | * 3 : Connection Status Event handle | ||
| 392 | */ | ||
| 393 | static void GetConnectionStatusEvent(Interface* self) { | ||
| 394 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0C, 1, 2); | ||
| 395 | |||
| 396 | rb.Push(RESULT_SUCCESS); | ||
| 397 | rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::conn_status_event).Unwrap()); | ||
| 398 | |||
| 399 | LOG_INFO(Service_IR, "called"); | ||
| 400 | } | ||
| 401 | |||
| 402 | /** | ||
| 403 | * IR::FinalizeIrNop service function | ||
| 404 | * Finalize ir:USER service. | ||
| 405 | * Outputs: | ||
| 406 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 407 | */ | ||
| 408 | static void FinalizeIrNop(Interface* self) { | ||
| 409 | if (connected_device) { | ||
| 410 | connected_device->OnDisconnect(); | ||
| 411 | connected_device = nullptr; | ||
| 412 | } | ||
| 413 | |||
| 414 | shared_memory = nullptr; | ||
| 415 | receive_buffer = boost::none; | ||
| 416 | |||
| 417 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x02, 1, 0); | ||
| 418 | rb.Push(RESULT_SUCCESS); | ||
| 419 | |||
| 420 | LOG_INFO(Service_IR, "called"); | ||
| 421 | } | ||
| 422 | |||
| 423 | /** | ||
| 424 | * IR::SendIrNop service function | ||
| 425 | * Sends a packet to the connected IR device | ||
| 426 | * Inpus: | ||
| 427 | * 1 : Size of data to send | ||
| 428 | * 2 : 2 + (size << 14) (Static buffer descriptor) | ||
| 429 | * 3 : Data buffer address | ||
| 430 | * Outputs: | ||
| 431 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 432 | */ | ||
| 433 | static void SendIrNop(Interface* self) { | ||
| 434 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 1, 2); | ||
| 435 | const u32 size = rp.Pop<u32>(); | ||
| 436 | const VAddr address = rp.PopStaticBuffer(); | ||
| 437 | |||
| 438 | std::vector<u8> buffer(size); | ||
| 439 | Memory::ReadBlock(address, buffer.data(), size); | ||
| 440 | |||
| 441 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 442 | if (connected_device) { | ||
| 443 | connected_device->OnReceive(buffer); | ||
| 444 | send_event->Signal(); | ||
| 445 | rb.Push(RESULT_SUCCESS); | ||
| 446 | } else { | ||
| 447 | LOG_ERROR(Service_IR, "not connected"); | ||
| 448 | rb.Push(ResultCode(static_cast<ErrorDescription>(13), ErrorModule::IR, | ||
| 449 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 450 | } | ||
| 451 | |||
| 452 | LOG_TRACE(Service_IR, "called, data=%s", Common::ArrayToString(buffer.data(), size).c_str()); | ||
| 453 | } | ||
| 454 | |||
| 455 | /** | ||
| 456 | * IR::ReleaseReceivedData function | ||
| 457 | * Release a specified amount of packet from the receive buffer. This is called after the | ||
| 458 | * application reads received packet from the buffer directly, to release the buffer space for | ||
| 459 | * future packets. | ||
| 460 | * Inpus: | ||
| 461 | * 1 : Number of packets to release | ||
| 462 | * Outputs: | ||
| 463 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 464 | */ | ||
| 465 | static void ReleaseReceivedData(Interface* self) { | ||
| 466 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x19, 1, 0); | ||
| 467 | u32 count = rp.Pop<u32>(); | ||
| 468 | |||
| 469 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 470 | |||
| 471 | if (receive_buffer->Release(count)) { | ||
| 472 | rb.Push(RESULT_SUCCESS); | ||
| 473 | } else { | ||
| 474 | LOG_ERROR(Service_IR, "failed to release %u packets", count); | ||
| 475 | rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::IR, ErrorSummary::NotFound, | ||
| 476 | ErrorLevel::Status)); | ||
| 477 | } | ||
| 478 | |||
| 479 | LOG_TRACE(Service_IR, "called, count=%u", count); | ||
| 480 | } | ||
| 481 | |||
| 482 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 483 | {0x00010182, nullptr, "InitializeIrNop"}, | ||
| 484 | {0x00020000, FinalizeIrNop, "FinalizeIrNop"}, | ||
| 485 | {0x00030000, nullptr, "ClearReceiveBuffer"}, | ||
| 486 | {0x00040000, nullptr, "ClearSendBuffer"}, | ||
| 487 | {0x000500C0, nullptr, "WaitConnection"}, | ||
| 488 | {0x00060040, RequireConnection, "RequireConnection"}, | ||
| 489 | {0x000702C0, nullptr, "AutoConnection"}, | ||
| 490 | {0x00080000, nullptr, "AnyConnection"}, | ||
| 491 | {0x00090000, Disconnect, "Disconnect"}, | ||
| 492 | {0x000A0000, GetReceiveEvent, "GetReceiveEvent"}, | ||
| 493 | {0x000B0000, GetSendEvent, "GetSendEvent"}, | ||
| 494 | {0x000C0000, GetConnectionStatusEvent, "GetConnectionStatusEvent"}, | ||
| 495 | {0x000D0042, SendIrNop, "SendIrNop"}, | ||
| 496 | {0x000E0042, nullptr, "SendIrNopLarge"}, | ||
| 497 | {0x000F0040, nullptr, "ReceiveIrnop"}, | ||
| 498 | {0x00100042, nullptr, "ReceiveIrnopLarge"}, | ||
| 499 | {0x00110040, nullptr, "GetLatestReceiveErrorResult"}, | ||
| 500 | {0x00120040, nullptr, "GetLatestSendErrorResult"}, | ||
| 501 | {0x00130000, nullptr, "GetConnectionStatus"}, | ||
| 502 | {0x00140000, nullptr, "GetTryingToConnectStatus"}, | ||
| 503 | {0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"}, | ||
| 504 | {0x00160000, nullptr, "GetSendSizeFreeAndUsed"}, | ||
| 505 | {0x00170000, nullptr, "GetConnectionRole"}, | ||
| 506 | {0x00180182, InitializeIrNopShared, "InitializeIrNopShared"}, | ||
| 507 | {0x00190040, ReleaseReceivedData, "ReleaseReceivedData"}, | ||
| 508 | {0x001A0040, nullptr, "SetOwnMachineId"}, | ||
| 509 | }; | ||
| 510 | |||
| 511 | IR_User_Interface::IR_User_Interface() { | ||
| 512 | Register(FunctionTable); | ||
| 513 | } | ||
| 514 | |||
| 515 | void InitUser() { | ||
| 516 | using namespace Kernel; | ||
| 517 | |||
| 518 | shared_memory = nullptr; | ||
| 519 | |||
| 520 | conn_status_event = Event::Create(ResetType::OneShot, "IR:ConnectionStatusEvent"); | ||
| 521 | send_event = Event::Create(ResetType::OneShot, "IR:SendEvent"); | ||
| 522 | receive_event = Event::Create(ResetType::OneShot, "IR:ReceiveEvent"); | ||
| 523 | |||
| 524 | receive_buffer = boost::none; | ||
| 525 | |||
| 526 | extra_hid = std::make_unique<ExtraHID>(PutToReceive); | ||
| 527 | |||
| 528 | connected_device = nullptr; | ||
| 529 | } | ||
| 530 | |||
| 531 | void ShutdownUser() { | ||
| 532 | if (connected_device) { | ||
| 533 | connected_device->OnDisconnect(); | ||
| 534 | connected_device = nullptr; | ||
| 535 | } | ||
| 536 | |||
| 537 | extra_hid = nullptr; | ||
| 538 | receive_buffer = boost::none; | ||
| 539 | shared_memory = nullptr; | ||
| 540 | conn_status_event = nullptr; | ||
| 541 | send_event = nullptr; | ||
| 542 | receive_event = nullptr; | ||
| 543 | } | ||
| 544 | |||
| 545 | void ReloadInputDevicesUser() { | ||
| 546 | if (extra_hid) | ||
| 547 | extra_hid->RequestInputDevicesReload(); | ||
| 548 | } | ||
| 549 | |||
| 550 | IRDevice::IRDevice(SendFunc send_func_) : send_func(send_func_) {} | ||
| 551 | IRDevice::~IRDevice() = default; | ||
| 552 | |||
| 553 | void IRDevice::Send(const std::vector<u8>& data) { | ||
| 554 | send_func(data); | ||
| 555 | } | ||
| 556 | |||
| 557 | } // namespace IR | ||
| 558 | } // namespace Service | ||
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h deleted file mode 100644 index 930650406..000000000 --- a/src/core/hle/service/ir/ir_user.h +++ /dev/null | |||
| @@ -1,58 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace IR { | ||
| 12 | |||
| 13 | /// An interface representing a device that can communicate with 3DS via ir:USER service | ||
| 14 | class IRDevice { | ||
| 15 | public: | ||
| 16 | /** | ||
| 17 | * A function object that implements the method to send data to the 3DS, which takes a vector of | ||
| 18 | * data to send. | ||
| 19 | */ | ||
| 20 | using SendFunc = std::function<void(const std::vector<u8>& data)>; | ||
| 21 | |||
| 22 | explicit IRDevice(SendFunc send_func); | ||
| 23 | virtual ~IRDevice(); | ||
| 24 | |||
| 25 | /// Called when connected with 3DS | ||
| 26 | virtual void OnConnect() = 0; | ||
| 27 | |||
| 28 | /// Called when disconnected from 3DS | ||
| 29 | virtual void OnDisconnect() = 0; | ||
| 30 | |||
| 31 | /// Called when data is received from the 3DS. This is invoked by the ir:USER send function. | ||
| 32 | virtual void OnReceive(const std::vector<u8>& data) = 0; | ||
| 33 | |||
| 34 | protected: | ||
| 35 | /// Sends data to the 3DS. The actual sending method is specified in the constructor | ||
| 36 | void Send(const std::vector<u8>& data); | ||
| 37 | |||
| 38 | private: | ||
| 39 | const SendFunc send_func; | ||
| 40 | }; | ||
| 41 | |||
| 42 | class IR_User_Interface : public Service::Interface { | ||
| 43 | public: | ||
| 44 | IR_User_Interface(); | ||
| 45 | |||
| 46 | std::string GetPortName() const override { | ||
| 47 | return "ir:USER"; | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | void InitUser(); | ||
| 52 | void ShutdownUser(); | ||
| 53 | |||
| 54 | /// Reload input devices. Used when input configuration changed | ||
| 55 | void ReloadInputDevicesUser(); | ||
| 56 | |||
| 57 | } // namespace IR | ||
| 58 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp deleted file mode 100644 index 6128f8a6c..000000000 --- a/src/core/hle/service/ldr_ro/cro_helper.cpp +++ /dev/null | |||
| @@ -1,1495 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/alignment.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/scope_exit.h" | ||
| 8 | #include "core/hle/service/ldr_ro/cro_helper.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace LDR { | ||
| 12 | |||
| 13 | static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F | ||
| 14 | ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, | ||
| 15 | ErrorLevel::Usage); | ||
| 16 | |||
| 17 | static ResultCode CROFormatError(u32 description) { | ||
| 18 | return ResultCode(static_cast<ErrorDescription>(description), ErrorModule::RO, | ||
| 19 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 20 | } | ||
| 21 | |||
| 22 | const std::array<int, 17> CROHelper::ENTRY_SIZE{{ | ||
| 23 | 1, // code | ||
| 24 | 1, // data | ||
| 25 | 1, // module name | ||
| 26 | sizeof(SegmentEntry), sizeof(ExportNamedSymbolEntry), sizeof(ExportIndexedSymbolEntry), | ||
| 27 | 1, // export strings | ||
| 28 | sizeof(ExportTreeEntry), sizeof(ImportModuleEntry), sizeof(ExternalRelocationEntry), | ||
| 29 | sizeof(ImportNamedSymbolEntry), sizeof(ImportIndexedSymbolEntry), | ||
| 30 | sizeof(ImportAnonymousSymbolEntry), | ||
| 31 | 1, // import strings | ||
| 32 | sizeof(StaticAnonymousSymbolEntry), sizeof(InternalRelocationEntry), | ||
| 33 | sizeof(StaticRelocationEntry), | ||
| 34 | }}; | ||
| 35 | |||
| 36 | const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS{{ | ||
| 37 | Fix0Barrier, Fix1Barrier, Fix2Barrier, Fix3Barrier, | ||
| 38 | }}; | ||
| 39 | |||
| 40 | VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const { | ||
| 41 | u32 segment_num = GetField(SegmentNum); | ||
| 42 | |||
| 43 | if (segment_tag.segment_index >= segment_num) | ||
| 44 | return 0; | ||
| 45 | |||
| 46 | SegmentEntry entry; | ||
| 47 | GetEntry(segment_tag.segment_index, entry); | ||
| 48 | |||
| 49 | if (segment_tag.offset_into_segment >= entry.size) | ||
| 50 | return 0; | ||
| 51 | |||
| 52 | return entry.offset + segment_tag.offset_into_segment; | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType relocation_type, | ||
| 56 | u32 addend, u32 symbol_address, u32 target_future_address) { | ||
| 57 | |||
| 58 | switch (relocation_type) { | ||
| 59 | case RelocationType::Nothing: | ||
| 60 | break; | ||
| 61 | case RelocationType::AbsoluteAddress: | ||
| 62 | case RelocationType::AbsoluteAddress2: | ||
| 63 | Memory::Write32(target_address, symbol_address + addend); | ||
| 64 | break; | ||
| 65 | case RelocationType::RelativeAddress: | ||
| 66 | Memory::Write32(target_address, symbol_address + addend - target_future_address); | ||
| 67 | break; | ||
| 68 | case RelocationType::ThumbBranch: | ||
| 69 | case RelocationType::ArmBranch: | ||
| 70 | case RelocationType::ModifyArmBranch: | ||
| 71 | case RelocationType::AlignedRelativeAddress: | ||
| 72 | // TODO(wwylele): implement other types | ||
| 73 | UNIMPLEMENTED(); | ||
| 74 | break; | ||
| 75 | default: | ||
| 76 | return CROFormatError(0x22); | ||
| 77 | } | ||
| 78 | return RESULT_SUCCESS; | ||
| 79 | } | ||
| 80 | |||
| 81 | ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType relocation_type) { | ||
| 82 | switch (relocation_type) { | ||
| 83 | case RelocationType::Nothing: | ||
| 84 | break; | ||
| 85 | case RelocationType::AbsoluteAddress: | ||
| 86 | case RelocationType::AbsoluteAddress2: | ||
| 87 | case RelocationType::RelativeAddress: | ||
| 88 | Memory::Write32(target_address, 0); | ||
| 89 | break; | ||
| 90 | case RelocationType::ThumbBranch: | ||
| 91 | case RelocationType::ArmBranch: | ||
| 92 | case RelocationType::ModifyArmBranch: | ||
| 93 | case RelocationType::AlignedRelativeAddress: | ||
| 94 | // TODO(wwylele): implement other types | ||
| 95 | UNIMPLEMENTED(); | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | return CROFormatError(0x22); | ||
| 99 | } | ||
| 100 | return RESULT_SUCCESS; | ||
| 101 | } | ||
| 102 | |||
| 103 | ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset) { | ||
| 104 | if (symbol_address == 0 && !reset) | ||
| 105 | return CROFormatError(0x10); | ||
| 106 | |||
| 107 | VAddr relocation_address = batch; | ||
| 108 | while (true) { | ||
| 109 | RelocationEntry relocation; | ||
| 110 | Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry)); | ||
| 111 | |||
| 112 | VAddr relocation_target = SegmentTagToAddress(relocation.target_position); | ||
| 113 | if (relocation_target == 0) { | ||
| 114 | return CROFormatError(0x12); | ||
| 115 | } | ||
| 116 | |||
| 117 | ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, | ||
| 118 | symbol_address, relocation_target); | ||
| 119 | if (result.IsError()) { | ||
| 120 | LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); | ||
| 121 | return result; | ||
| 122 | } | ||
| 123 | |||
| 124 | if (relocation.is_batch_end) | ||
| 125 | break; | ||
| 126 | |||
| 127 | relocation_address += sizeof(RelocationEntry); | ||
| 128 | } | ||
| 129 | |||
| 130 | RelocationEntry relocation; | ||
| 131 | Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry)); | ||
| 132 | relocation.is_batch_resolved = reset ? 0 : 1; | ||
| 133 | Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry)); | ||
| 134 | return RESULT_SUCCESS; | ||
| 135 | } | ||
| 136 | |||
| 137 | VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const { | ||
| 138 | if (!GetField(ExportTreeNum)) | ||
| 139 | return 0; | ||
| 140 | |||
| 141 | std::size_t len = name.size(); | ||
| 142 | ExportTreeEntry entry; | ||
| 143 | GetEntry(0, entry); | ||
| 144 | ExportTreeEntry::Child next; | ||
| 145 | next.raw = entry.left.raw; | ||
| 146 | u32 found_id; | ||
| 147 | |||
| 148 | while (true) { | ||
| 149 | GetEntry(next.next_index, entry); | ||
| 150 | |||
| 151 | if (next.is_end) { | ||
| 152 | found_id = entry.export_table_index; | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | u16 test_byte = entry.test_bit >> 3; | ||
| 157 | u16 test_bit_in_byte = entry.test_bit & 7; | ||
| 158 | |||
| 159 | if (test_byte >= len) { | ||
| 160 | next.raw = entry.left.raw; | ||
| 161 | } else if ((name[test_byte] >> test_bit_in_byte) & 1) { | ||
| 162 | next.raw = entry.right.raw; | ||
| 163 | } else { | ||
| 164 | next.raw = entry.left.raw; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); | ||
| 169 | |||
| 170 | if (found_id >= export_named_symbol_num) | ||
| 171 | return 0; | ||
| 172 | |||
| 173 | u32 export_strings_size = GetField(ExportStringsSize); | ||
| 174 | ExportNamedSymbolEntry symbol_entry; | ||
| 175 | GetEntry(found_id, symbol_entry); | ||
| 176 | |||
| 177 | if (Memory::ReadCString(symbol_entry.name_offset, export_strings_size) != name) | ||
| 178 | return 0; | ||
| 179 | |||
| 180 | return SegmentTagToAddress(symbol_entry.symbol_position); | ||
| 181 | } | ||
| 182 | |||
| 183 | ResultCode CROHelper::RebaseHeader(u32 cro_size) { | ||
| 184 | ResultCode error = CROFormatError(0x11); | ||
| 185 | |||
| 186 | // verifies magic | ||
| 187 | if (GetField(Magic) != MAGIC_CRO0) | ||
| 188 | return error; | ||
| 189 | |||
| 190 | // verifies not registered | ||
| 191 | if (GetField(NextCRO) != 0 || GetField(PreviousCRO) != 0) | ||
| 192 | return error; | ||
| 193 | |||
| 194 | // This seems to be a hard limit set by the RO module | ||
| 195 | if (GetField(FileSize) > 0x10000000 || GetField(BssSize) > 0x10000000) | ||
| 196 | return error; | ||
| 197 | |||
| 198 | // verifies not fixed | ||
| 199 | if (GetField(FixedSize) != 0) | ||
| 200 | return error; | ||
| 201 | |||
| 202 | if (GetField(CodeOffset) < CRO_HEADER_SIZE) | ||
| 203 | return error; | ||
| 204 | |||
| 205 | // verifies that all offsets are in the correct order | ||
| 206 | constexpr std::array<HeaderField, 18> OFFSET_ORDER = {{ | ||
| 207 | CodeOffset, ModuleNameOffset, SegmentTableOffset, ExportNamedSymbolTableOffset, | ||
| 208 | ExportTreeTableOffset, ExportIndexedSymbolTableOffset, ExportStringsOffset, | ||
| 209 | ImportModuleTableOffset, ExternalRelocationTableOffset, ImportNamedSymbolTableOffset, | ||
| 210 | ImportIndexedSymbolTableOffset, ImportAnonymousSymbolTableOffset, ImportStringsOffset, | ||
| 211 | StaticAnonymousSymbolTableOffset, InternalRelocationTableOffset, | ||
| 212 | StaticRelocationTableOffset, DataOffset, FileSize, | ||
| 213 | }}; | ||
| 214 | |||
| 215 | u32 prev_offset = GetField(OFFSET_ORDER[0]); | ||
| 216 | u32 cur_offset; | ||
| 217 | for (std::size_t i = 1; i < OFFSET_ORDER.size(); ++i) { | ||
| 218 | cur_offset = GetField(OFFSET_ORDER[i]); | ||
| 219 | if (cur_offset < prev_offset) | ||
| 220 | return error; | ||
| 221 | prev_offset = cur_offset; | ||
| 222 | } | ||
| 223 | |||
| 224 | // rebases offsets | ||
| 225 | u32 offset = GetField(NameOffset); | ||
| 226 | if (offset != 0) | ||
| 227 | SetField(NameOffset, offset + module_address); | ||
| 228 | |||
| 229 | for (int field = CodeOffset; field < Fix0Barrier; field += 2) { | ||
| 230 | HeaderField header_field = static_cast<HeaderField>(field); | ||
| 231 | offset = GetField(header_field); | ||
| 232 | if (offset != 0) | ||
| 233 | SetField(header_field, offset + module_address); | ||
| 234 | } | ||
| 235 | |||
| 236 | // verifies everything is not beyond the buffer | ||
| 237 | u32 file_end = module_address + cro_size; | ||
| 238 | for (int field = CodeOffset, i = 0; field < Fix0Barrier; field += 2, ++i) { | ||
| 239 | HeaderField offset_field = static_cast<HeaderField>(field); | ||
| 240 | HeaderField size_field = static_cast<HeaderField>(field + 1); | ||
| 241 | if (GetField(offset_field) + GetField(size_field) * ENTRY_SIZE[i] > file_end) | ||
| 242 | return error; | ||
| 243 | } | ||
| 244 | |||
| 245 | return RESULT_SUCCESS; | ||
| 246 | } | ||
| 247 | |||
| 248 | ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_address, | ||
| 249 | u32 data_segment_size, VAddr bss_segment_address, | ||
| 250 | u32 bss_segment_size) { | ||
| 251 | |||
| 252 | u32 prev_data_segment = 0; | ||
| 253 | u32 segment_num = GetField(SegmentNum); | ||
| 254 | for (u32 i = 0; i < segment_num; ++i) { | ||
| 255 | SegmentEntry segment; | ||
| 256 | GetEntry(i, segment); | ||
| 257 | if (segment.type == SegmentType::Data) { | ||
| 258 | if (segment.size != 0) { | ||
| 259 | if (segment.size > data_segment_size) | ||
| 260 | return ERROR_BUFFER_TOO_SMALL; | ||
| 261 | prev_data_segment = segment.offset; | ||
| 262 | segment.offset = data_segment_address; | ||
| 263 | } | ||
| 264 | } else if (segment.type == SegmentType::BSS) { | ||
| 265 | if (segment.size != 0) { | ||
| 266 | if (segment.size > bss_segment_size) | ||
| 267 | return ERROR_BUFFER_TOO_SMALL; | ||
| 268 | segment.offset = bss_segment_address; | ||
| 269 | } | ||
| 270 | } else if (segment.offset != 0) { | ||
| 271 | segment.offset += module_address; | ||
| 272 | if (segment.offset > module_address + cro_size) | ||
| 273 | return CROFormatError(0x19); | ||
| 274 | } | ||
| 275 | SetEntry(i, segment); | ||
| 276 | } | ||
| 277 | return MakeResult<VAddr>(prev_data_segment + module_address); | ||
| 278 | } | ||
| 279 | |||
| 280 | ResultCode CROHelper::RebaseExportNamedSymbolTable() { | ||
| 281 | VAddr export_strings_offset = GetField(ExportStringsOffset); | ||
| 282 | VAddr export_strings_end = export_strings_offset + GetField(ExportStringsSize); | ||
| 283 | |||
| 284 | u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); | ||
| 285 | for (u32 i = 0; i < export_named_symbol_num; ++i) { | ||
| 286 | ExportNamedSymbolEntry entry; | ||
| 287 | GetEntry(i, entry); | ||
| 288 | |||
| 289 | if (entry.name_offset != 0) { | ||
| 290 | entry.name_offset += module_address; | ||
| 291 | if (entry.name_offset < export_strings_offset || | ||
| 292 | entry.name_offset >= export_strings_end) { | ||
| 293 | return CROFormatError(0x11); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | SetEntry(i, entry); | ||
| 298 | } | ||
| 299 | return RESULT_SUCCESS; | ||
| 300 | } | ||
| 301 | |||
| 302 | ResultCode CROHelper::VerifyExportTreeTable() const { | ||
| 303 | u32 tree_num = GetField(ExportTreeNum); | ||
| 304 | for (u32 i = 0; i < tree_num; ++i) { | ||
| 305 | ExportTreeEntry entry; | ||
| 306 | GetEntry(i, entry); | ||
| 307 | |||
| 308 | if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) { | ||
| 309 | return CROFormatError(0x11); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | return RESULT_SUCCESS; | ||
| 313 | } | ||
| 314 | |||
| 315 | ResultCode CROHelper::RebaseImportModuleTable() { | ||
| 316 | VAddr import_strings_offset = GetField(ImportStringsOffset); | ||
| 317 | VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); | ||
| 318 | VAddr import_indexed_symbol_table_offset = GetField(ImportIndexedSymbolTableOffset); | ||
| 319 | VAddr index_import_table_end = | ||
| 320 | import_indexed_symbol_table_offset + | ||
| 321 | GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry); | ||
| 322 | VAddr import_anonymous_symbol_table_offset = GetField(ImportAnonymousSymbolTableOffset); | ||
| 323 | VAddr offset_import_table_end = | ||
| 324 | import_anonymous_symbol_table_offset + | ||
| 325 | GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry); | ||
| 326 | |||
| 327 | u32 module_num = GetField(ImportModuleNum); | ||
| 328 | for (u32 i = 0; i < module_num; ++i) { | ||
| 329 | ImportModuleEntry entry; | ||
| 330 | GetEntry(i, entry); | ||
| 331 | |||
| 332 | if (entry.name_offset != 0) { | ||
| 333 | entry.name_offset += module_address; | ||
| 334 | if (entry.name_offset < import_strings_offset || | ||
| 335 | entry.name_offset >= import_strings_end) { | ||
| 336 | return CROFormatError(0x18); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | if (entry.import_indexed_symbol_table_offset != 0) { | ||
| 341 | entry.import_indexed_symbol_table_offset += module_address; | ||
| 342 | if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset || | ||
| 343 | entry.import_indexed_symbol_table_offset > index_import_table_end) { | ||
| 344 | return CROFormatError(0x18); | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | if (entry.import_anonymous_symbol_table_offset != 0) { | ||
| 349 | entry.import_anonymous_symbol_table_offset += module_address; | ||
| 350 | if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset || | ||
| 351 | entry.import_anonymous_symbol_table_offset > offset_import_table_end) { | ||
| 352 | return CROFormatError(0x18); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | SetEntry(i, entry); | ||
| 357 | } | ||
| 358 | return RESULT_SUCCESS; | ||
| 359 | } | ||
| 360 | |||
| 361 | ResultCode CROHelper::RebaseImportNamedSymbolTable() { | ||
| 362 | VAddr import_strings_offset = GetField(ImportStringsOffset); | ||
| 363 | VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize); | ||
| 364 | VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); | ||
| 365 | VAddr external_relocation_table_end = | ||
| 366 | external_relocation_table_offset + | ||
| 367 | GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); | ||
| 368 | |||
| 369 | u32 num = GetField(ImportNamedSymbolNum); | ||
| 370 | for (u32 i = 0; i < num; ++i) { | ||
| 371 | ImportNamedSymbolEntry entry; | ||
| 372 | GetEntry(i, entry); | ||
| 373 | |||
| 374 | if (entry.name_offset != 0) { | ||
| 375 | entry.name_offset += module_address; | ||
| 376 | if (entry.name_offset < import_strings_offset || | ||
| 377 | entry.name_offset >= import_strings_end) { | ||
| 378 | return CROFormatError(0x1B); | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | if (entry.relocation_batch_offset != 0) { | ||
| 383 | entry.relocation_batch_offset += module_address; | ||
| 384 | if (entry.relocation_batch_offset < external_relocation_table_offset || | ||
| 385 | entry.relocation_batch_offset > external_relocation_table_end) { | ||
| 386 | return CROFormatError(0x1B); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | SetEntry(i, entry); | ||
| 391 | } | ||
| 392 | return RESULT_SUCCESS; | ||
| 393 | } | ||
| 394 | |||
| 395 | ResultCode CROHelper::RebaseImportIndexedSymbolTable() { | ||
| 396 | VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); | ||
| 397 | VAddr external_relocation_table_end = | ||
| 398 | external_relocation_table_offset + | ||
| 399 | GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); | ||
| 400 | |||
| 401 | u32 num = GetField(ImportIndexedSymbolNum); | ||
| 402 | for (u32 i = 0; i < num; ++i) { | ||
| 403 | ImportIndexedSymbolEntry entry; | ||
| 404 | GetEntry(i, entry); | ||
| 405 | |||
| 406 | if (entry.relocation_batch_offset != 0) { | ||
| 407 | entry.relocation_batch_offset += module_address; | ||
| 408 | if (entry.relocation_batch_offset < external_relocation_table_offset || | ||
| 409 | entry.relocation_batch_offset > external_relocation_table_end) { | ||
| 410 | return CROFormatError(0x14); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | SetEntry(i, entry); | ||
| 415 | } | ||
| 416 | return RESULT_SUCCESS; | ||
| 417 | } | ||
| 418 | |||
| 419 | ResultCode CROHelper::RebaseImportAnonymousSymbolTable() { | ||
| 420 | VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset); | ||
| 421 | VAddr external_relocation_table_end = | ||
| 422 | external_relocation_table_offset + | ||
| 423 | GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry); | ||
| 424 | |||
| 425 | u32 num = GetField(ImportAnonymousSymbolNum); | ||
| 426 | for (u32 i = 0; i < num; ++i) { | ||
| 427 | ImportAnonymousSymbolEntry entry; | ||
| 428 | GetEntry(i, entry); | ||
| 429 | |||
| 430 | if (entry.relocation_batch_offset != 0) { | ||
| 431 | entry.relocation_batch_offset += module_address; | ||
| 432 | if (entry.relocation_batch_offset < external_relocation_table_offset || | ||
| 433 | entry.relocation_batch_offset > external_relocation_table_end) { | ||
| 434 | return CROFormatError(0x17); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | SetEntry(i, entry); | ||
| 439 | } | ||
| 440 | return RESULT_SUCCESS; | ||
| 441 | } | ||
| 442 | |||
| 443 | VAddr CROHelper::GetOnUnresolvedAddress() { | ||
| 444 | return SegmentTagToAddress(SegmentTag(GetField(OnUnresolvedSegmentTag))); | ||
| 445 | } | ||
| 446 | |||
| 447 | ResultCode CROHelper::ResetExternalRelocations() { | ||
| 448 | u32 unresolved_symbol = GetOnUnresolvedAddress(); | ||
| 449 | u32 external_relocation_num = GetField(ExternalRelocationNum); | ||
| 450 | ExternalRelocationEntry relocation; | ||
| 451 | |||
| 452 | // Verifies that the last relocation is the end of a batch | ||
| 453 | GetEntry(external_relocation_num - 1, relocation); | ||
| 454 | if (!relocation.is_batch_end) { | ||
| 455 | return CROFormatError(0x12); | ||
| 456 | } | ||
| 457 | |||
| 458 | bool batch_begin = true; | ||
| 459 | for (u32 i = 0; i < external_relocation_num; ++i) { | ||
| 460 | GetEntry(i, relocation); | ||
| 461 | VAddr relocation_target = SegmentTagToAddress(relocation.target_position); | ||
| 462 | |||
| 463 | if (relocation_target == 0) { | ||
| 464 | return CROFormatError(0x12); | ||
| 465 | } | ||
| 466 | |||
| 467 | ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, | ||
| 468 | unresolved_symbol, relocation_target); | ||
| 469 | if (result.IsError()) { | ||
| 470 | LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); | ||
| 471 | return result; | ||
| 472 | } | ||
| 473 | |||
| 474 | if (batch_begin) { | ||
| 475 | // resets to unresolved state | ||
| 476 | relocation.is_batch_resolved = 0; | ||
| 477 | SetEntry(i, relocation); | ||
| 478 | } | ||
| 479 | |||
| 480 | // if current is an end, then the next is a beginning | ||
| 481 | batch_begin = relocation.is_batch_end != 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | return RESULT_SUCCESS; | ||
| 485 | } | ||
| 486 | |||
| 487 | ResultCode CROHelper::ClearExternalRelocations() { | ||
| 488 | u32 external_relocation_num = GetField(ExternalRelocationNum); | ||
| 489 | ExternalRelocationEntry relocation; | ||
| 490 | |||
| 491 | bool batch_begin = true; | ||
| 492 | for (u32 i = 0; i < external_relocation_num; ++i) { | ||
| 493 | GetEntry(i, relocation); | ||
| 494 | VAddr relocation_target = SegmentTagToAddress(relocation.target_position); | ||
| 495 | |||
| 496 | if (relocation_target == 0) { | ||
| 497 | return CROFormatError(0x12); | ||
| 498 | } | ||
| 499 | |||
| 500 | ResultCode result = ClearRelocation(relocation_target, relocation.type); | ||
| 501 | if (result.IsError()) { | ||
| 502 | LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); | ||
| 503 | return result; | ||
| 504 | } | ||
| 505 | |||
| 506 | if (batch_begin) { | ||
| 507 | // resets to unresolved state | ||
| 508 | relocation.is_batch_resolved = 0; | ||
| 509 | SetEntry(i, relocation); | ||
| 510 | } | ||
| 511 | |||
| 512 | // if current is an end, then the next is a beginning | ||
| 513 | batch_begin = relocation.is_batch_end != 0; | ||
| 514 | } | ||
| 515 | |||
| 516 | return RESULT_SUCCESS; | ||
| 517 | } | ||
| 518 | |||
| 519 | ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) { | ||
| 520 | VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset); | ||
| 521 | VAddr static_relocation_table_end = | ||
| 522 | static_relocation_table_offset + | ||
| 523 | GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry); | ||
| 524 | |||
| 525 | CROHelper crs(crs_address); | ||
| 526 | u32 offset_export_num = GetField(StaticAnonymousSymbolNum); | ||
| 527 | LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(), | ||
| 528 | offset_export_num); | ||
| 529 | for (u32 i = 0; i < offset_export_num; ++i) { | ||
| 530 | StaticAnonymousSymbolEntry entry; | ||
| 531 | GetEntry(i, entry); | ||
| 532 | u32 batch_address = entry.relocation_batch_offset + module_address; | ||
| 533 | |||
| 534 | if (batch_address < static_relocation_table_offset || | ||
| 535 | batch_address > static_relocation_table_end) { | ||
| 536 | return CROFormatError(0x16); | ||
| 537 | } | ||
| 538 | |||
| 539 | u32 symbol_address = SegmentTagToAddress(entry.symbol_position); | ||
| 540 | LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", | ||
| 541 | ModuleName().data(), symbol_address); | ||
| 542 | ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address); | ||
| 543 | if (result.IsError()) { | ||
| 544 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 545 | return result; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | return RESULT_SUCCESS; | ||
| 549 | } | ||
| 550 | |||
| 551 | ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) { | ||
| 552 | u32 segment_num = GetField(SegmentNum); | ||
| 553 | u32 internal_relocation_num = GetField(InternalRelocationNum); | ||
| 554 | for (u32 i = 0; i < internal_relocation_num; ++i) { | ||
| 555 | InternalRelocationEntry relocation; | ||
| 556 | GetEntry(i, relocation); | ||
| 557 | VAddr target_addressB = SegmentTagToAddress(relocation.target_position); | ||
| 558 | if (target_addressB == 0) { | ||
| 559 | return CROFormatError(0x15); | ||
| 560 | } | ||
| 561 | |||
| 562 | VAddr target_address; | ||
| 563 | SegmentEntry target_segment; | ||
| 564 | GetEntry(relocation.target_position.segment_index, target_segment); | ||
| 565 | |||
| 566 | if (target_segment.type == SegmentType::Data) { | ||
| 567 | // If the relocation is to the .data segment, we need to relocate it in the old buffer | ||
| 568 | target_address = | ||
| 569 | old_data_segment_address + relocation.target_position.offset_into_segment; | ||
| 570 | } else { | ||
| 571 | target_address = target_addressB; | ||
| 572 | } | ||
| 573 | |||
| 574 | if (relocation.symbol_segment >= segment_num) { | ||
| 575 | return CROFormatError(0x15); | ||
| 576 | } | ||
| 577 | |||
| 578 | SegmentEntry symbol_segment; | ||
| 579 | GetEntry(relocation.symbol_segment, symbol_segment); | ||
| 580 | LOG_TRACE(Service_LDR, "Internally relocates 0x%08X with 0x%08X", target_address, | ||
| 581 | symbol_segment.offset); | ||
| 582 | ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend, | ||
| 583 | symbol_segment.offset, target_addressB); | ||
| 584 | if (result.IsError()) { | ||
| 585 | LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw); | ||
| 586 | return result; | ||
| 587 | } | ||
| 588 | } | ||
| 589 | return RESULT_SUCCESS; | ||
| 590 | } | ||
| 591 | |||
| 592 | ResultCode CROHelper::ClearInternalRelocations() { | ||
| 593 | u32 internal_relocation_num = GetField(InternalRelocationNum); | ||
| 594 | for (u32 i = 0; i < internal_relocation_num; ++i) { | ||
| 595 | InternalRelocationEntry relocation; | ||
| 596 | GetEntry(i, relocation); | ||
| 597 | VAddr target_address = SegmentTagToAddress(relocation.target_position); | ||
| 598 | |||
| 599 | if (target_address == 0) { | ||
| 600 | return CROFormatError(0x15); | ||
| 601 | } | ||
| 602 | |||
| 603 | ResultCode result = ClearRelocation(target_address, relocation.type); | ||
| 604 | if (result.IsError()) { | ||
| 605 | LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw); | ||
| 606 | return result; | ||
| 607 | } | ||
| 608 | } | ||
| 609 | return RESULT_SUCCESS; | ||
| 610 | } | ||
| 611 | |||
| 612 | void CROHelper::UnrebaseImportAnonymousSymbolTable() { | ||
| 613 | u32 num = GetField(ImportAnonymousSymbolNum); | ||
| 614 | for (u32 i = 0; i < num; ++i) { | ||
| 615 | ImportAnonymousSymbolEntry entry; | ||
| 616 | GetEntry(i, entry); | ||
| 617 | |||
| 618 | if (entry.relocation_batch_offset != 0) { | ||
| 619 | entry.relocation_batch_offset -= module_address; | ||
| 620 | } | ||
| 621 | |||
| 622 | SetEntry(i, entry); | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | void CROHelper::UnrebaseImportIndexedSymbolTable() { | ||
| 627 | u32 num = GetField(ImportIndexedSymbolNum); | ||
| 628 | for (u32 i = 0; i < num; ++i) { | ||
| 629 | ImportIndexedSymbolEntry entry; | ||
| 630 | GetEntry(i, entry); | ||
| 631 | |||
| 632 | if (entry.relocation_batch_offset != 0) { | ||
| 633 | entry.relocation_batch_offset -= module_address; | ||
| 634 | } | ||
| 635 | |||
| 636 | SetEntry(i, entry); | ||
| 637 | } | ||
| 638 | } | ||
| 639 | |||
| 640 | void CROHelper::UnrebaseImportNamedSymbolTable() { | ||
| 641 | u32 num = GetField(ImportNamedSymbolNum); | ||
| 642 | for (u32 i = 0; i < num; ++i) { | ||
| 643 | ImportNamedSymbolEntry entry; | ||
| 644 | GetEntry(i, entry); | ||
| 645 | |||
| 646 | if (entry.name_offset != 0) { | ||
| 647 | entry.name_offset -= module_address; | ||
| 648 | } | ||
| 649 | |||
| 650 | if (entry.relocation_batch_offset) { | ||
| 651 | entry.relocation_batch_offset -= module_address; | ||
| 652 | } | ||
| 653 | |||
| 654 | SetEntry(i, entry); | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 658 | void CROHelper::UnrebaseImportModuleTable() { | ||
| 659 | u32 module_num = GetField(ImportModuleNum); | ||
| 660 | for (u32 i = 0; i < module_num; ++i) { | ||
| 661 | ImportModuleEntry entry; | ||
| 662 | GetEntry(i, entry); | ||
| 663 | |||
| 664 | if (entry.name_offset != 0) { | ||
| 665 | entry.name_offset -= module_address; | ||
| 666 | } | ||
| 667 | |||
| 668 | if (entry.import_indexed_symbol_table_offset) { | ||
| 669 | entry.import_indexed_symbol_table_offset -= module_address; | ||
| 670 | } | ||
| 671 | |||
| 672 | if (entry.import_anonymous_symbol_table_offset) { | ||
| 673 | entry.import_anonymous_symbol_table_offset -= module_address; | ||
| 674 | } | ||
| 675 | |||
| 676 | SetEntry(i, entry); | ||
| 677 | } | ||
| 678 | } | ||
| 679 | |||
| 680 | void CROHelper::UnrebaseExportNamedSymbolTable() { | ||
| 681 | u32 export_named_symbol_num = GetField(ExportNamedSymbolNum); | ||
| 682 | for (u32 i = 0; i < export_named_symbol_num; ++i) { | ||
| 683 | ExportNamedSymbolEntry entry; | ||
| 684 | GetEntry(i, entry); | ||
| 685 | |||
| 686 | if (entry.name_offset != 0) { | ||
| 687 | entry.name_offset -= module_address; | ||
| 688 | } | ||
| 689 | |||
| 690 | SetEntry(i, entry); | ||
| 691 | } | ||
| 692 | } | ||
| 693 | |||
| 694 | void CROHelper::UnrebaseSegmentTable() { | ||
| 695 | u32 segment_num = GetField(SegmentNum); | ||
| 696 | for (u32 i = 0; i < segment_num; ++i) { | ||
| 697 | SegmentEntry segment; | ||
| 698 | GetEntry(i, segment); | ||
| 699 | |||
| 700 | if (segment.type == SegmentType::BSS) { | ||
| 701 | segment.offset = 0; | ||
| 702 | } else if (segment.offset != 0) { | ||
| 703 | segment.offset -= module_address; | ||
| 704 | } | ||
| 705 | |||
| 706 | SetEntry(i, segment); | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | void CROHelper::UnrebaseHeader() { | ||
| 711 | u32 offset = GetField(NameOffset); | ||
| 712 | if (offset != 0) | ||
| 713 | SetField(NameOffset, offset - module_address); | ||
| 714 | |||
| 715 | for (int field = CodeOffset; field < Fix0Barrier; field += 2) { | ||
| 716 | HeaderField header_field = static_cast<HeaderField>(field); | ||
| 717 | offset = GetField(header_field); | ||
| 718 | if (offset != 0) | ||
| 719 | SetField(header_field, offset - module_address); | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) { | ||
| 724 | u32 import_strings_size = GetField(ImportStringsSize); | ||
| 725 | u32 symbol_import_num = GetField(ImportNamedSymbolNum); | ||
| 726 | for (u32 i = 0; i < symbol_import_num; ++i) { | ||
| 727 | ImportNamedSymbolEntry entry; | ||
| 728 | GetEntry(i, entry); | ||
| 729 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 730 | ExternalRelocationEntry relocation_entry; | ||
| 731 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 732 | |||
| 733 | if (!relocation_entry.is_batch_resolved) { | ||
| 734 | ResultCode result = | ||
| 735 | ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { | ||
| 736 | std::string symbol_name = | ||
| 737 | Memory::ReadCString(entry.name_offset, import_strings_size); | ||
| 738 | u32 symbol_address = source.FindExportNamedSymbol(symbol_name); | ||
| 739 | |||
| 740 | if (symbol_address != 0) { | ||
| 741 | LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"", | ||
| 742 | ModuleName().data(), symbol_name.data(), | ||
| 743 | source.ModuleName().data()); | ||
| 744 | |||
| 745 | ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); | ||
| 746 | if (result.IsError()) { | ||
| 747 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", | ||
| 748 | result.raw); | ||
| 749 | return result; | ||
| 750 | } | ||
| 751 | |||
| 752 | return MakeResult<bool>(false); | ||
| 753 | } | ||
| 754 | |||
| 755 | return MakeResult<bool>(true); | ||
| 756 | }); | ||
| 757 | if (result.IsError()) { | ||
| 758 | return result; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | } | ||
| 762 | return RESULT_SUCCESS; | ||
| 763 | } | ||
| 764 | |||
| 765 | ResultCode CROHelper::ResetImportNamedSymbol() { | ||
| 766 | u32 unresolved_symbol = GetOnUnresolvedAddress(); | ||
| 767 | |||
| 768 | u32 symbol_import_num = GetField(ImportNamedSymbolNum); | ||
| 769 | for (u32 i = 0; i < symbol_import_num; ++i) { | ||
| 770 | ImportNamedSymbolEntry entry; | ||
| 771 | GetEntry(i, entry); | ||
| 772 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 773 | ExternalRelocationEntry relocation_entry; | ||
| 774 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 775 | |||
| 776 | ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); | ||
| 777 | if (result.IsError()) { | ||
| 778 | LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); | ||
| 779 | return result; | ||
| 780 | } | ||
| 781 | } | ||
| 782 | return RESULT_SUCCESS; | ||
| 783 | } | ||
| 784 | |||
| 785 | ResultCode CROHelper::ResetImportIndexedSymbol() { | ||
| 786 | u32 unresolved_symbol = GetOnUnresolvedAddress(); | ||
| 787 | |||
| 788 | u32 import_num = GetField(ImportIndexedSymbolNum); | ||
| 789 | for (u32 i = 0; i < import_num; ++i) { | ||
| 790 | ImportIndexedSymbolEntry entry; | ||
| 791 | GetEntry(i, entry); | ||
| 792 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 793 | ExternalRelocationEntry relocation_entry; | ||
| 794 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 795 | |||
| 796 | ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); | ||
| 797 | if (result.IsError()) { | ||
| 798 | LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); | ||
| 799 | return result; | ||
| 800 | } | ||
| 801 | } | ||
| 802 | return RESULT_SUCCESS; | ||
| 803 | } | ||
| 804 | |||
| 805 | ResultCode CROHelper::ResetImportAnonymousSymbol() { | ||
| 806 | u32 unresolved_symbol = GetOnUnresolvedAddress(); | ||
| 807 | |||
| 808 | u32 import_num = GetField(ImportAnonymousSymbolNum); | ||
| 809 | for (u32 i = 0; i < import_num; ++i) { | ||
| 810 | ImportAnonymousSymbolEntry entry; | ||
| 811 | GetEntry(i, entry); | ||
| 812 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 813 | ExternalRelocationEntry relocation_entry; | ||
| 814 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 815 | |||
| 816 | ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); | ||
| 817 | if (result.IsError()) { | ||
| 818 | LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw); | ||
| 819 | return result; | ||
| 820 | } | ||
| 821 | } | ||
| 822 | return RESULT_SUCCESS; | ||
| 823 | } | ||
| 824 | |||
| 825 | ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) { | ||
| 826 | u32 import_strings_size = GetField(ImportStringsSize); | ||
| 827 | |||
| 828 | u32 import_module_num = GetField(ImportModuleNum); | ||
| 829 | for (u32 i = 0; i < import_module_num; ++i) { | ||
| 830 | ImportModuleEntry entry; | ||
| 831 | GetEntry(i, entry); | ||
| 832 | std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size); | ||
| 833 | |||
| 834 | ResultCode result = | ||
| 835 | ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { | ||
| 836 | if (want_cro_name == source.ModuleName()) { | ||
| 837 | LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"", | ||
| 838 | ModuleName().data(), entry.import_indexed_symbol_num, | ||
| 839 | source.ModuleName().data()); | ||
| 840 | for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { | ||
| 841 | ImportIndexedSymbolEntry im; | ||
| 842 | entry.GetImportIndexedSymbolEntry(j, im); | ||
| 843 | ExportIndexedSymbolEntry ex; | ||
| 844 | source.GetEntry(im.index, ex); | ||
| 845 | u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position); | ||
| 846 | LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); | ||
| 847 | ResultCode result = | ||
| 848 | ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); | ||
| 849 | if (result.IsError()) { | ||
| 850 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", | ||
| 851 | result.raw); | ||
| 852 | return result; | ||
| 853 | } | ||
| 854 | } | ||
| 855 | LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"", | ||
| 856 | ModuleName().data(), entry.import_anonymous_symbol_num, | ||
| 857 | source.ModuleName().data()); | ||
| 858 | for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { | ||
| 859 | ImportAnonymousSymbolEntry im; | ||
| 860 | entry.GetImportAnonymousSymbolEntry(j, im); | ||
| 861 | u32 symbol_address = source.SegmentTagToAddress(im.symbol_position); | ||
| 862 | LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address); | ||
| 863 | ResultCode result = | ||
| 864 | ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); | ||
| 865 | if (result.IsError()) { | ||
| 866 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", | ||
| 867 | result.raw); | ||
| 868 | return result; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | return MakeResult<bool>(false); | ||
| 872 | } | ||
| 873 | return MakeResult<bool>(true); | ||
| 874 | }); | ||
| 875 | if (result.IsError()) { | ||
| 876 | return result; | ||
| 877 | } | ||
| 878 | } | ||
| 879 | return RESULT_SUCCESS; | ||
| 880 | } | ||
| 881 | |||
| 882 | ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) { | ||
| 883 | LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"", ModuleName().data(), | ||
| 884 | target.ModuleName().data()); | ||
| 885 | u32 target_import_strings_size = target.GetField(ImportStringsSize); | ||
| 886 | u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); | ||
| 887 | for (u32 i = 0; i < target_symbol_import_num; ++i) { | ||
| 888 | ImportNamedSymbolEntry entry; | ||
| 889 | target.GetEntry(i, entry); | ||
| 890 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 891 | ExternalRelocationEntry relocation_entry; | ||
| 892 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 893 | |||
| 894 | if (!relocation_entry.is_batch_resolved) { | ||
| 895 | std::string symbol_name = | ||
| 896 | Memory::ReadCString(entry.name_offset, target_import_strings_size); | ||
| 897 | u32 symbol_address = FindExportNamedSymbol(symbol_name); | ||
| 898 | if (symbol_address != 0) { | ||
| 899 | LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data()); | ||
| 900 | ResultCode result = target.ApplyRelocationBatch(relocation_addr, symbol_address); | ||
| 901 | if (result.IsError()) { | ||
| 902 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 903 | return result; | ||
| 904 | } | ||
| 905 | } | ||
| 906 | } | ||
| 907 | } | ||
| 908 | return RESULT_SUCCESS; | ||
| 909 | } | ||
| 910 | |||
| 911 | ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) { | ||
| 912 | LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"", ModuleName().data(), | ||
| 913 | target.ModuleName().data()); | ||
| 914 | u32 unresolved_symbol = target.GetOnUnresolvedAddress(); | ||
| 915 | u32 target_import_strings_size = target.GetField(ImportStringsSize); | ||
| 916 | u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum); | ||
| 917 | for (u32 i = 0; i < target_symbol_import_num; ++i) { | ||
| 918 | ImportNamedSymbolEntry entry; | ||
| 919 | target.GetEntry(i, entry); | ||
| 920 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 921 | ExternalRelocationEntry relocation_entry; | ||
| 922 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 923 | |||
| 924 | if (relocation_entry.is_batch_resolved) { | ||
| 925 | std::string symbol_name = | ||
| 926 | Memory::ReadCString(entry.name_offset, target_import_strings_size); | ||
| 927 | u32 symbol_address = FindExportNamedSymbol(symbol_name); | ||
| 928 | if (symbol_address != 0) { | ||
| 929 | LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data()); | ||
| 930 | ResultCode result = | ||
| 931 | target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); | ||
| 932 | if (result.IsError()) { | ||
| 933 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 934 | return result; | ||
| 935 | } | ||
| 936 | } | ||
| 937 | } | ||
| 938 | } | ||
| 939 | return RESULT_SUCCESS; | ||
| 940 | } | ||
| 941 | |||
| 942 | ResultCode CROHelper::ApplyModuleExport(CROHelper target) { | ||
| 943 | std::string module_name = ModuleName(); | ||
| 944 | u32 target_import_string_size = target.GetField(ImportStringsSize); | ||
| 945 | u32 target_import_module_num = target.GetField(ImportModuleNum); | ||
| 946 | for (u32 i = 0; i < target_import_module_num; ++i) { | ||
| 947 | ImportModuleEntry entry; | ||
| 948 | target.GetEntry(i, entry); | ||
| 949 | |||
| 950 | if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) | ||
| 951 | continue; | ||
| 952 | |||
| 953 | LOG_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"", module_name.data(), | ||
| 954 | entry.import_indexed_symbol_num, target.ModuleName().data()); | ||
| 955 | for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { | ||
| 956 | ImportIndexedSymbolEntry im; | ||
| 957 | entry.GetImportIndexedSymbolEntry(j, im); | ||
| 958 | ExportIndexedSymbolEntry ex; | ||
| 959 | GetEntry(im.index, ex); | ||
| 960 | u32 symbol_address = SegmentTagToAddress(ex.symbol_position); | ||
| 961 | LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); | ||
| 962 | ResultCode result = | ||
| 963 | target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); | ||
| 964 | if (result.IsError()) { | ||
| 965 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 966 | return result; | ||
| 967 | } | ||
| 968 | } | ||
| 969 | |||
| 970 | LOG_INFO(Service_LDR, "CRO \"%s\" exports %d anonymous symbols to \"%s\"", | ||
| 971 | module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data()); | ||
| 972 | for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { | ||
| 973 | ImportAnonymousSymbolEntry im; | ||
| 974 | entry.GetImportAnonymousSymbolEntry(j, im); | ||
| 975 | u32 symbol_address = SegmentTagToAddress(im.symbol_position); | ||
| 976 | LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address); | ||
| 977 | ResultCode result = | ||
| 978 | target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address); | ||
| 979 | if (result.IsError()) { | ||
| 980 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 981 | return result; | ||
| 982 | } | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | return RESULT_SUCCESS; | ||
| 987 | } | ||
| 988 | |||
| 989 | ResultCode CROHelper::ResetModuleExport(CROHelper target) { | ||
| 990 | u32 unresolved_symbol = target.GetOnUnresolvedAddress(); | ||
| 991 | |||
| 992 | std::string module_name = ModuleName(); | ||
| 993 | u32 target_import_string_size = target.GetField(ImportStringsSize); | ||
| 994 | u32 target_import_module_num = target.GetField(ImportModuleNum); | ||
| 995 | for (u32 i = 0; i < target_import_module_num; ++i) { | ||
| 996 | ImportModuleEntry entry; | ||
| 997 | target.GetEntry(i, entry); | ||
| 998 | |||
| 999 | if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name) | ||
| 1000 | continue; | ||
| 1001 | |||
| 1002 | LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"", module_name.data(), | ||
| 1003 | target.ModuleName().data()); | ||
| 1004 | for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { | ||
| 1005 | ImportIndexedSymbolEntry im; | ||
| 1006 | entry.GetImportIndexedSymbolEntry(j, im); | ||
| 1007 | ResultCode result = | ||
| 1008 | target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); | ||
| 1009 | if (result.IsError()) { | ||
| 1010 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 1011 | return result; | ||
| 1012 | } | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports anonymous symbols to \"%s\"", | ||
| 1016 | module_name.data(), target.ModuleName().data()); | ||
| 1017 | for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { | ||
| 1018 | ImportAnonymousSymbolEntry im; | ||
| 1019 | entry.GetImportAnonymousSymbolEntry(j, im); | ||
| 1020 | ResultCode result = | ||
| 1021 | target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); | ||
| 1022 | if (result.IsError()) { | ||
| 1023 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw); | ||
| 1024 | return result; | ||
| 1025 | } | ||
| 1026 | } | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | return RESULT_SUCCESS; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) { | ||
| 1033 | u32 import_strings_size = GetField(ImportStringsSize); | ||
| 1034 | u32 symbol_import_num = GetField(ImportNamedSymbolNum); | ||
| 1035 | for (u32 i = 0; i < symbol_import_num; ++i) { | ||
| 1036 | ImportNamedSymbolEntry entry; | ||
| 1037 | GetEntry(i, entry); | ||
| 1038 | VAddr relocation_addr = entry.relocation_batch_offset; | ||
| 1039 | ExternalRelocationEntry relocation_entry; | ||
| 1040 | Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); | ||
| 1041 | |||
| 1042 | if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") { | ||
| 1043 | ResultCode result = | ||
| 1044 | ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { | ||
| 1045 | u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_"); | ||
| 1046 | |||
| 1047 | if (symbol_address != 0) { | ||
| 1048 | LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"", | ||
| 1049 | ModuleName().data(), source.ModuleName().data()); | ||
| 1050 | |||
| 1051 | ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address); | ||
| 1052 | if (result.IsError()) { | ||
| 1053 | LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", | ||
| 1054 | result.raw); | ||
| 1055 | return result; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | return MakeResult<bool>(false); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | return MakeResult<bool>(true); | ||
| 1062 | }); | ||
| 1063 | if (result.IsError()) { | ||
| 1064 | LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw); | ||
| 1065 | return result; | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | return RESULT_SUCCESS; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | /** | ||
| 1073 | * Verifies a string or a string table matching a predicted size (i.e. terminated by 0) | ||
| 1074 | * if it is not empty. There can be many other nulls in the string table because | ||
| 1075 | * they are composed by many sub strings. This function is to check whether the | ||
| 1076 | * whole string (table) is terminated properly, despite that it is not actually one string. | ||
| 1077 | * @param address the virtual address of the string (table) | ||
| 1078 | * @param size the size of the string (table), including the terminating 0 | ||
| 1079 | * @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code. | ||
| 1080 | */ | ||
| 1081 | static ResultCode VerifyStringTableLength(VAddr address, u32 size) { | ||
| 1082 | if (size != 0) { | ||
| 1083 | if (Memory::Read8(address + size - 1) != 0) | ||
| 1084 | return CROFormatError(0x0B); | ||
| 1085 | } | ||
| 1086 | return RESULT_SUCCESS; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_addresss, | ||
| 1090 | u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size, | ||
| 1091 | bool is_crs) { | ||
| 1092 | |||
| 1093 | ResultCode result = RebaseHeader(cro_size); | ||
| 1094 | if (result.IsError()) { | ||
| 1095 | LOG_ERROR(Service_LDR, "Error rebasing header %08X", result.raw); | ||
| 1096 | return result; | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | result = VerifyStringTableLength(GetField(ModuleNameOffset), GetField(ModuleNameSize)); | ||
| 1100 | if (result.IsError()) { | ||
| 1101 | LOG_ERROR(Service_LDR, "Error verifying module name %08X", result.raw); | ||
| 1102 | return result; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | u32 prev_data_segment_address = 0; | ||
| 1106 | if (!is_crs) { | ||
| 1107 | auto result_val = RebaseSegmentTable(cro_size, data_segment_addresss, data_segment_size, | ||
| 1108 | bss_segment_address, bss_segment_size); | ||
| 1109 | if (result_val.Failed()) { | ||
| 1110 | LOG_ERROR(Service_LDR, "Error rebasing segment table %08X", result_val.Code().raw); | ||
| 1111 | return result_val.Code(); | ||
| 1112 | } | ||
| 1113 | prev_data_segment_address = *result_val; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | result = RebaseExportNamedSymbolTable(); | ||
| 1117 | if (result.IsError()) { | ||
| 1118 | LOG_ERROR(Service_LDR, "Error rebasing symbol export table %08X", result.raw); | ||
| 1119 | return result; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | result = VerifyExportTreeTable(); | ||
| 1123 | if (result.IsError()) { | ||
| 1124 | LOG_ERROR(Service_LDR, "Error verifying export tree %08X", result.raw); | ||
| 1125 | return result; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | result = VerifyStringTableLength(GetField(ExportStringsOffset), GetField(ExportStringsSize)); | ||
| 1129 | if (result.IsError()) { | ||
| 1130 | LOG_ERROR(Service_LDR, "Error verifying export strings %08X", result.raw); | ||
| 1131 | return result; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | result = RebaseImportModuleTable(); | ||
| 1135 | if (result.IsError()) { | ||
| 1136 | LOG_ERROR(Service_LDR, "Error rebasing object table %08X", result.raw); | ||
| 1137 | return result; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | result = ResetExternalRelocations(); | ||
| 1141 | if (result.IsError()) { | ||
| 1142 | LOG_ERROR(Service_LDR, "Error resetting all external relocations %08X", result.raw); | ||
| 1143 | return result; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | result = RebaseImportNamedSymbolTable(); | ||
| 1147 | if (result.IsError()) { | ||
| 1148 | LOG_ERROR(Service_LDR, "Error rebasing symbol import table %08X", result.raw); | ||
| 1149 | return result; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | result = RebaseImportIndexedSymbolTable(); | ||
| 1153 | if (result.IsError()) { | ||
| 1154 | LOG_ERROR(Service_LDR, "Error rebasing index import table %08X", result.raw); | ||
| 1155 | return result; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | result = RebaseImportAnonymousSymbolTable(); | ||
| 1159 | if (result.IsError()) { | ||
| 1160 | LOG_ERROR(Service_LDR, "Error rebasing offset import table %08X", result.raw); | ||
| 1161 | return result; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | result = VerifyStringTableLength(GetField(ImportStringsOffset), GetField(ImportStringsSize)); | ||
| 1165 | if (result.IsError()) { | ||
| 1166 | LOG_ERROR(Service_LDR, "Error verifying import strings %08X", result.raw); | ||
| 1167 | return result; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | if (!is_crs) { | ||
| 1171 | result = ApplyStaticAnonymousSymbolToCRS(crs_address); | ||
| 1172 | if (result.IsError()) { | ||
| 1173 | LOG_ERROR(Service_LDR, "Error applying offset export to CRS %08X", result.raw); | ||
| 1174 | return result; | ||
| 1175 | } | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | result = ApplyInternalRelocations(prev_data_segment_address); | ||
| 1179 | if (result.IsError()) { | ||
| 1180 | LOG_ERROR(Service_LDR, "Error applying internal relocations %08X", result.raw); | ||
| 1181 | return result; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | if (!is_crs) { | ||
| 1185 | result = ApplyExitRelocations(crs_address); | ||
| 1186 | if (result.IsError()) { | ||
| 1187 | LOG_ERROR(Service_LDR, "Error applying exit relocations %08X", result.raw); | ||
| 1188 | return result; | ||
| 1189 | } | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | return RESULT_SUCCESS; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | void CROHelper::Unrebase(bool is_crs) { | ||
| 1196 | UnrebaseImportAnonymousSymbolTable(); | ||
| 1197 | UnrebaseImportIndexedSymbolTable(); | ||
| 1198 | UnrebaseImportNamedSymbolTable(); | ||
| 1199 | UnrebaseImportModuleTable(); | ||
| 1200 | UnrebaseExportNamedSymbolTable(); | ||
| 1201 | |||
| 1202 | if (!is_crs) | ||
| 1203 | UnrebaseSegmentTable(); | ||
| 1204 | |||
| 1205 | SetNextModule(0); | ||
| 1206 | SetPreviousModule(0); | ||
| 1207 | |||
| 1208 | SetField(FixedSize, 0); | ||
| 1209 | |||
| 1210 | UnrebaseHeader(); | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | ResultCode CROHelper::VerifyHash(u32 cro_size, VAddr crr) const { | ||
| 1214 | // TODO(wwylele): actually verify the hash | ||
| 1215 | return RESULT_SUCCESS; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) { | ||
| 1219 | ResultCode result = RESULT_SUCCESS; | ||
| 1220 | |||
| 1221 | { | ||
| 1222 | VAddr data_segment_address; | ||
| 1223 | if (link_on_load_bug_fix) { | ||
| 1224 | // this is a bug fix introduced by 7.2.0-17's LoadCRO_New | ||
| 1225 | // The bug itself is: | ||
| 1226 | // If a relocation target is in .data segment, it will relocate to the | ||
| 1227 | // user-specified buffer. But if this is linking during loading, | ||
| 1228 | // the .data segment hasn't been transfer from CRO to the buffer, | ||
| 1229 | // thus the relocation will be overwritten by data transfer. | ||
| 1230 | // To fix this bug, we need temporarily restore the old .data segment | ||
| 1231 | // offset and apply imported symbols. | ||
| 1232 | |||
| 1233 | // RO service seems assuming segment_index == segment_type, | ||
| 1234 | // so we do the same | ||
| 1235 | if (GetField(SegmentNum) >= 2) { // means we have .data segment | ||
| 1236 | SegmentEntry entry; | ||
| 1237 | GetEntry(2, entry); | ||
| 1238 | ASSERT(entry.type == SegmentType::Data); | ||
| 1239 | data_segment_address = entry.offset; | ||
| 1240 | entry.offset = GetField(DataOffset); | ||
| 1241 | SetEntry(2, entry); | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | SCOPE_EXIT({ | ||
| 1245 | // Restore the new .data segment address after importing | ||
| 1246 | if (link_on_load_bug_fix) { | ||
| 1247 | if (GetField(SegmentNum) >= 2) { | ||
| 1248 | SegmentEntry entry; | ||
| 1249 | GetEntry(2, entry); | ||
| 1250 | entry.offset = data_segment_address; | ||
| 1251 | SetEntry(2, entry); | ||
| 1252 | } | ||
| 1253 | } | ||
| 1254 | }); | ||
| 1255 | |||
| 1256 | // Imports named symbols from other modules | ||
| 1257 | result = ApplyImportNamedSymbol(crs_address); | ||
| 1258 | if (result.IsError()) { | ||
| 1259 | LOG_ERROR(Service_LDR, "Error applying symbol import %08X", result.raw); | ||
| 1260 | return result; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | // Imports indexed and anonymous symbols from other modules | ||
| 1264 | result = ApplyModuleImport(crs_address); | ||
| 1265 | if (result.IsError()) { | ||
| 1266 | LOG_ERROR(Service_LDR, "Error applying module import %08X", result.raw); | ||
| 1267 | return result; | ||
| 1268 | } | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | // Exports symbols to other modules | ||
| 1272 | result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { | ||
| 1273 | ResultCode result = ApplyExportNamedSymbol(target); | ||
| 1274 | if (result.IsError()) | ||
| 1275 | return result; | ||
| 1276 | |||
| 1277 | result = ApplyModuleExport(target); | ||
| 1278 | if (result.IsError()) | ||
| 1279 | return result; | ||
| 1280 | |||
| 1281 | return MakeResult<bool>(true); | ||
| 1282 | }); | ||
| 1283 | if (result.IsError()) { | ||
| 1284 | LOG_ERROR(Service_LDR, "Error applying export %08X", result.raw); | ||
| 1285 | return result; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | return RESULT_SUCCESS; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | ResultCode CROHelper::Unlink(VAddr crs_address) { | ||
| 1292 | |||
| 1293 | // Resets all imported named symbols | ||
| 1294 | ResultCode result = ResetImportNamedSymbol(); | ||
| 1295 | if (result.IsError()) { | ||
| 1296 | LOG_ERROR(Service_LDR, "Error resetting symbol import %08X", result.raw); | ||
| 1297 | return result; | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | // Resets all imported indexed symbols | ||
| 1301 | result = ResetImportIndexedSymbol(); | ||
| 1302 | if (result.IsError()) { | ||
| 1303 | LOG_ERROR(Service_LDR, "Error resetting indexed import %08X", result.raw); | ||
| 1304 | return result; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | // Resets all imported anonymous symbols | ||
| 1308 | result = ResetImportAnonymousSymbol(); | ||
| 1309 | if (result.IsError()) { | ||
| 1310 | LOG_ERROR(Service_LDR, "Error resetting anonymous import %08X", result.raw); | ||
| 1311 | return result; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | // Resets all symbols in other modules imported from this module | ||
| 1315 | // Note: the RO service seems only searching in auto-link modules | ||
| 1316 | result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { | ||
| 1317 | ResultCode result = ResetExportNamedSymbol(target); | ||
| 1318 | if (result.IsError()) | ||
| 1319 | return result; | ||
| 1320 | |||
| 1321 | result = ResetModuleExport(target); | ||
| 1322 | if (result.IsError()) | ||
| 1323 | return result; | ||
| 1324 | |||
| 1325 | return MakeResult<bool>(true); | ||
| 1326 | }); | ||
| 1327 | if (result.IsError()) { | ||
| 1328 | LOG_ERROR(Service_LDR, "Error resetting export %08X", result.raw); | ||
| 1329 | return result; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | return RESULT_SUCCESS; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | ResultCode CROHelper::ClearRelocations() { | ||
| 1336 | ResultCode result = ClearExternalRelocations(); | ||
| 1337 | if (result.IsError()) { | ||
| 1338 | LOG_ERROR(Service_LDR, "Error clearing external relocations %08X", result.raw); | ||
| 1339 | return result; | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | result = ClearInternalRelocations(); | ||
| 1343 | if (result.IsError()) { | ||
| 1344 | LOG_ERROR(Service_LDR, "Error clearing internal relocations %08X", result.raw); | ||
| 1345 | return result; | ||
| 1346 | } | ||
| 1347 | return RESULT_SUCCESS; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | void CROHelper::InitCRS() { | ||
| 1351 | SetNextModule(0); | ||
| 1352 | SetPreviousModule(0); | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | void CROHelper::Register(VAddr crs_address, bool auto_link) { | ||
| 1356 | CROHelper crs(crs_address); | ||
| 1357 | CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule()); | ||
| 1358 | |||
| 1359 | if (head.module_address) { | ||
| 1360 | // there are already CROs registered | ||
| 1361 | // register as the new tail | ||
| 1362 | CROHelper tail(head.PreviousModule()); | ||
| 1363 | |||
| 1364 | // link with the old tail | ||
| 1365 | ASSERT(tail.NextModule() == 0); | ||
| 1366 | SetPreviousModule(tail.module_address); | ||
| 1367 | tail.SetNextModule(module_address); | ||
| 1368 | |||
| 1369 | // set previous of the head pointing to the new tail | ||
| 1370 | head.SetPreviousModule(module_address); | ||
| 1371 | } else { | ||
| 1372 | // register as the first CRO | ||
| 1373 | // set previous to self as tail | ||
| 1374 | SetPreviousModule(module_address); | ||
| 1375 | |||
| 1376 | // set self as head | ||
| 1377 | if (auto_link) | ||
| 1378 | crs.SetNextModule(module_address); | ||
| 1379 | else | ||
| 1380 | crs.SetPreviousModule(module_address); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | // the new one is the tail | ||
| 1384 | SetNextModule(0); | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | void CROHelper::Unregister(VAddr crs_address) { | ||
| 1388 | CROHelper crs(crs_address); | ||
| 1389 | CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule()); | ||
| 1390 | CROHelper next(NextModule()), previous(PreviousModule()); | ||
| 1391 | |||
| 1392 | if (module_address == next_head.module_address || | ||
| 1393 | module_address == previous_head.module_address) { | ||
| 1394 | // removing head | ||
| 1395 | if (next.module_address) { | ||
| 1396 | // the next is new head | ||
| 1397 | // let its previous point to the tail | ||
| 1398 | next.SetPreviousModule(previous.module_address); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | // set new head | ||
| 1402 | if (module_address == previous_head.module_address) { | ||
| 1403 | crs.SetPreviousModule(next.module_address); | ||
| 1404 | } else { | ||
| 1405 | crs.SetNextModule(next.module_address); | ||
| 1406 | } | ||
| 1407 | } else if (next.module_address) { | ||
| 1408 | // link previous and next | ||
| 1409 | previous.SetNextModule(next.module_address); | ||
| 1410 | next.SetPreviousModule(previous.module_address); | ||
| 1411 | } else { | ||
| 1412 | // removing tail | ||
| 1413 | // set previous as new tail | ||
| 1414 | previous.SetNextModule(0); | ||
| 1415 | |||
| 1416 | // let head's previous point to the new tail | ||
| 1417 | if (next_head.module_address && next_head.PreviousModule() == module_address) { | ||
| 1418 | next_head.SetPreviousModule(previous.module_address); | ||
| 1419 | } else if (previous_head.module_address && | ||
| 1420 | previous_head.PreviousModule() == module_address) { | ||
| 1421 | previous_head.SetPreviousModule(previous.module_address); | ||
| 1422 | } else { | ||
| 1423 | UNREACHABLE(); | ||
| 1424 | } | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | // unlink self | ||
| 1428 | SetNextModule(0); | ||
| 1429 | SetPreviousModule(0); | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | u32 CROHelper::GetFixEnd(u32 fix_level) const { | ||
| 1433 | u32 end = CRO_HEADER_SIZE; | ||
| 1434 | end = std::max<u32>(end, GetField(CodeOffset) + GetField(CodeSize)); | ||
| 1435 | |||
| 1436 | u32 entry_size_i = 2; | ||
| 1437 | int field = ModuleNameOffset; | ||
| 1438 | while (true) { | ||
| 1439 | end = std::max<u32>(end, GetField(static_cast<HeaderField>(field)) + | ||
| 1440 | GetField(static_cast<HeaderField>(field + 1)) * | ||
| 1441 | ENTRY_SIZE[entry_size_i]); | ||
| 1442 | |||
| 1443 | ++entry_size_i; | ||
| 1444 | field += 2; | ||
| 1445 | |||
| 1446 | if (field == FIX_BARRIERS[fix_level]) | ||
| 1447 | return end; | ||
| 1448 | } | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | u32 CROHelper::Fix(u32 fix_level) { | ||
| 1452 | u32 fix_end = GetFixEnd(fix_level); | ||
| 1453 | |||
| 1454 | if (fix_level != 0) { | ||
| 1455 | SetField(Magic, MAGIC_FIXD); | ||
| 1456 | |||
| 1457 | for (int field = FIX_BARRIERS[fix_level]; field < Fix0Barrier; field += 2) { | ||
| 1458 | SetField(static_cast<HeaderField>(field), fix_end); | ||
| 1459 | SetField(static_cast<HeaderField>(field + 1), 0); | ||
| 1460 | } | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE); | ||
| 1464 | |||
| 1465 | u32 fixed_size = fix_end - module_address; | ||
| 1466 | SetField(FixedSize, fixed_size); | ||
| 1467 | return fixed_size; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | bool CROHelper::IsLoaded() const { | ||
| 1471 | u32 magic = GetField(Magic); | ||
| 1472 | if (magic != MAGIC_CRO0 && magic != MAGIC_FIXD) | ||
| 1473 | return false; | ||
| 1474 | |||
| 1475 | // TODO(wwylele): verify memory state here after memory aliasing is implemented | ||
| 1476 | |||
| 1477 | return true; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const { | ||
| 1481 | u32 segment_num = GetField(SegmentNum); | ||
| 1482 | for (u32 i = 0; i < segment_num; ++i) { | ||
| 1483 | SegmentEntry entry; | ||
| 1484 | GetEntry(i, entry); | ||
| 1485 | if (entry.type == SegmentType::Code && entry.size != 0) { | ||
| 1486 | VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); | ||
| 1487 | VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); | ||
| 1488 | return std::make_tuple(begin, end - begin); | ||
| 1489 | } | ||
| 1490 | } | ||
| 1491 | return std::make_tuple(0, 0); | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | } // namespace LDR | ||
| 1495 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h deleted file mode 100644 index 57b4fb6df..000000000 --- a/src/core/hle/service/ldr_ro/cro_helper.h +++ /dev/null | |||
| @@ -1,714 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <tuple> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | #include "core/memory.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace LDR { | ||
| 16 | |||
| 17 | // GCC versions < 5.0 do not implement std::is_trivially_copyable. | ||
| 18 | // Excluding MSVC because it has weird behaviour for std::is_trivially_copyable. | ||
| 19 | #if (__GNUC__ >= 5) || defined(__clang__) | ||
| 20 | #define ASSERT_CRO_STRUCT(name, size) \ | ||
| 21 | static_assert(std::is_standard_layout<name>::value, \ | ||
| 22 | "CRO structure " #name " doesn't use standard layout"); \ | ||
| 23 | static_assert(std::is_trivially_copyable<name>::value, \ | ||
| 24 | "CRO structure " #name " isn't trivially copyable"); \ | ||
| 25 | static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) | ||
| 26 | #else | ||
| 27 | #define ASSERT_CRO_STRUCT(name, size) \ | ||
| 28 | static_assert(std::is_standard_layout<name>::value, \ | ||
| 29 | "CRO structure " #name " doesn't use standard layout"); \ | ||
| 30 | static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | static constexpr u32 CRO_HEADER_SIZE = 0x138; | ||
| 34 | static constexpr u32 CRO_HASH_SIZE = 0x80; | ||
| 35 | |||
| 36 | /// Represents a loaded module (CRO) with interfaces manipulating it. | ||
| 37 | class CROHelper final { | ||
| 38 | public: | ||
| 39 | explicit CROHelper(VAddr cro_address) : module_address(cro_address) {} | ||
| 40 | |||
| 41 | std::string ModuleName() const { | ||
| 42 | return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize)); | ||
| 43 | } | ||
| 44 | |||
| 45 | u32 GetFileSize() const { | ||
| 46 | return GetField(FileSize); | ||
| 47 | } | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Rebases the module according to its address. | ||
| 51 | * @param crs_address the virtual address of the static module | ||
| 52 | * @param cro_size the size of the CRO file | ||
| 53 | * @param data_segment_address buffer address for .data segment | ||
| 54 | * @param data_segment_size the buffer size for .data segment | ||
| 55 | * @param bss_segment_address the buffer address for .bss segment | ||
| 56 | * @param bss_segment_size the buffer size for .bss segment | ||
| 57 | * @param is_crs true if the module itself is the static module | ||
| 58 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 59 | */ | ||
| 60 | ResultCode Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_address, | ||
| 61 | u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size, | ||
| 62 | bool is_crs); | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Unrebases the module. | ||
| 66 | * @param is_crs true if the module itself is the static module | ||
| 67 | */ | ||
| 68 | void Unrebase(bool is_crs); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Verifies module hash by CRR. | ||
| 72 | * @param cro_size the size of the CRO | ||
| 73 | * @param crr the virtual address of the CRR | ||
| 74 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 75 | */ | ||
| 76 | ResultCode VerifyHash(u32 cro_size, VAddr crr) const; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Links this module with all registered auto-link module. | ||
| 80 | * @param crs_address the virtual address of the static module | ||
| 81 | * @param link_on_load_bug_fix true if links when loading and fixes the bug | ||
| 82 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 83 | */ | ||
| 84 | ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Unlinks this module with other modules. | ||
| 88 | * @param crs_address the virtual address of the static module | ||
| 89 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 90 | */ | ||
| 91 | ResultCode Unlink(VAddr crs_address); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Clears all relocations to zero. | ||
| 95 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 96 | */ | ||
| 97 | ResultCode ClearRelocations(); | ||
| 98 | |||
| 99 | /// Initialize this module as the static module (CRS) | ||
| 100 | void InitCRS(); | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Registers this module and adds it to the module list. | ||
| 104 | * @param crs_address the virtual address of the static module | ||
| 105 | * @param auto_link whether to register as an auto link module | ||
| 106 | */ | ||
| 107 | void Register(VAddr crs_address, bool auto_link); | ||
| 108 | |||
| 109 | /** | ||
| 110 | * Unregisters this module and removes from the module list. | ||
| 111 | * @param crs_address the virtual address of the static module | ||
| 112 | */ | ||
| 113 | void Unregister(VAddr crs_address); | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Gets the end of reserved data according to the fix level. | ||
| 117 | * @param fix_level fix level from 0 to 3 | ||
| 118 | * @returns the end of reserved data. | ||
| 119 | */ | ||
| 120 | u32 GetFixEnd(u32 fix_level) const; | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Zeros offsets to cropped data according to the fix level and marks as fixed. | ||
| 124 | * @param fix_level fix level from 0 to 3 | ||
| 125 | * @returns page-aligned size of the module after fixing. | ||
| 126 | */ | ||
| 127 | u32 Fix(u32 fix_level); | ||
| 128 | |||
| 129 | bool IsFixed() const { | ||
| 130 | return GetField(Magic) == MAGIC_FIXD; | ||
| 131 | } | ||
| 132 | |||
| 133 | u32 GetFixedSize() const { | ||
| 134 | return GetField(FixedSize); | ||
| 135 | } | ||
| 136 | |||
| 137 | bool IsLoaded() const; | ||
| 138 | |||
| 139 | /** | ||
| 140 | * Gets the page address and size of the code segment. | ||
| 141 | * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist. | ||
| 142 | */ | ||
| 143 | std::tuple<VAddr, u32> GetExecutablePages() const; | ||
| 144 | |||
| 145 | private: | ||
| 146 | const VAddr module_address; ///< the virtual address of this module | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Each item in this enum represents a u32 field in the header begin from address+0x80, | ||
| 150 | * successively. We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or | ||
| 151 | * Read/WriteBlock repeatedly. | ||
| 152 | */ | ||
| 153 | enum HeaderField { | ||
| 154 | Magic = 0, | ||
| 155 | NameOffset, | ||
| 156 | NextCRO, | ||
| 157 | PreviousCRO, | ||
| 158 | FileSize, | ||
| 159 | BssSize, | ||
| 160 | FixedSize, | ||
| 161 | UnknownZero, | ||
| 162 | UnkSegmentTag, | ||
| 163 | OnLoadSegmentTag, | ||
| 164 | OnExitSegmentTag, | ||
| 165 | OnUnresolvedSegmentTag, | ||
| 166 | |||
| 167 | CodeOffset, | ||
| 168 | CodeSize, | ||
| 169 | DataOffset, | ||
| 170 | DataSize, | ||
| 171 | ModuleNameOffset, | ||
| 172 | ModuleNameSize, | ||
| 173 | SegmentTableOffset, | ||
| 174 | SegmentNum, | ||
| 175 | |||
| 176 | ExportNamedSymbolTableOffset, | ||
| 177 | ExportNamedSymbolNum, | ||
| 178 | ExportIndexedSymbolTableOffset, | ||
| 179 | ExportIndexedSymbolNum, | ||
| 180 | ExportStringsOffset, | ||
| 181 | ExportStringsSize, | ||
| 182 | ExportTreeTableOffset, | ||
| 183 | ExportTreeNum, | ||
| 184 | |||
| 185 | ImportModuleTableOffset, | ||
| 186 | ImportModuleNum, | ||
| 187 | ExternalRelocationTableOffset, | ||
| 188 | ExternalRelocationNum, | ||
| 189 | ImportNamedSymbolTableOffset, | ||
| 190 | ImportNamedSymbolNum, | ||
| 191 | ImportIndexedSymbolTableOffset, | ||
| 192 | ImportIndexedSymbolNum, | ||
| 193 | ImportAnonymousSymbolTableOffset, | ||
| 194 | ImportAnonymousSymbolNum, | ||
| 195 | ImportStringsOffset, | ||
| 196 | ImportStringsSize, | ||
| 197 | |||
| 198 | StaticAnonymousSymbolTableOffset, | ||
| 199 | StaticAnonymousSymbolNum, | ||
| 200 | InternalRelocationTableOffset, | ||
| 201 | InternalRelocationNum, | ||
| 202 | StaticRelocationTableOffset, | ||
| 203 | StaticRelocationNum, | ||
| 204 | Fix0Barrier, | ||
| 205 | |||
| 206 | Fix3Barrier = ExportNamedSymbolTableOffset, | ||
| 207 | Fix2Barrier = ImportModuleTableOffset, | ||
| 208 | Fix1Barrier = StaticAnonymousSymbolTableOffset, | ||
| 209 | }; | ||
| 210 | static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4, | ||
| 211 | "CRO Header fields are wrong!"); | ||
| 212 | |||
| 213 | enum class SegmentType : u32 { | ||
| 214 | Code = 0, | ||
| 215 | ROData = 1, | ||
| 216 | Data = 2, | ||
| 217 | BSS = 3, | ||
| 218 | }; | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Identifies a program location inside of a segment. | ||
| 222 | * Required to refer to program locations because individual segments may be relocated | ||
| 223 | * independently of each other. | ||
| 224 | */ | ||
| 225 | union SegmentTag { | ||
| 226 | u32_le raw; | ||
| 227 | BitField<0, 4, u32_le> segment_index; | ||
| 228 | BitField<4, 28, u32_le> offset_into_segment; | ||
| 229 | |||
| 230 | SegmentTag() = default; | ||
| 231 | explicit SegmentTag(u32 raw_) : raw(raw_) {} | ||
| 232 | }; | ||
| 233 | |||
| 234 | /// Information of a segment in this module. | ||
| 235 | struct SegmentEntry { | ||
| 236 | u32_le offset; | ||
| 237 | u32_le size; | ||
| 238 | SegmentType type; | ||
| 239 | |||
| 240 | static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset; | ||
| 241 | }; | ||
| 242 | ASSERT_CRO_STRUCT(SegmentEntry, 12); | ||
| 243 | |||
| 244 | /// Identifies a named symbol exported from this module. | ||
| 245 | struct ExportNamedSymbolEntry { | ||
| 246 | u32_le name_offset; // pointing to a substring in ExportStrings | ||
| 247 | SegmentTag symbol_position; // to self's segment | ||
| 248 | |||
| 249 | static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset; | ||
| 250 | }; | ||
| 251 | ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8); | ||
| 252 | |||
| 253 | /// Identifies an indexed symbol exported from this module. | ||
| 254 | struct ExportIndexedSymbolEntry { | ||
| 255 | SegmentTag symbol_position; // to self's segment | ||
| 256 | |||
| 257 | static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset; | ||
| 258 | }; | ||
| 259 | ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4); | ||
| 260 | |||
| 261 | /// A tree node in the symbol lookup tree. | ||
| 262 | struct ExportTreeEntry { | ||
| 263 | u16_le test_bit; // bit address into the name to test | ||
| 264 | union Child { | ||
| 265 | u16_le raw; | ||
| 266 | BitField<0, 15, u16_le> next_index; | ||
| 267 | BitField<15, 1, u16_le> is_end; | ||
| 268 | } left, right; | ||
| 269 | u16_le export_table_index; // index of an ExportNamedSymbolEntry | ||
| 270 | |||
| 271 | static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset; | ||
| 272 | }; | ||
| 273 | ASSERT_CRO_STRUCT(ExportTreeEntry, 8); | ||
| 274 | |||
| 275 | /// Identifies a named symbol imported from another module. | ||
| 276 | struct ImportNamedSymbolEntry { | ||
| 277 | u32_le name_offset; // pointing to a substring in ImportStrings | ||
| 278 | u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable | ||
| 279 | |||
| 280 | static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset; | ||
| 281 | }; | ||
| 282 | ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8); | ||
| 283 | |||
| 284 | /// Identifies an indexed symbol imported from another module. | ||
| 285 | struct ImportIndexedSymbolEntry { | ||
| 286 | u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module | ||
| 287 | u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable | ||
| 288 | |||
| 289 | static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset; | ||
| 290 | }; | ||
| 291 | ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8); | ||
| 292 | |||
| 293 | /// Identifies an anonymous symbol imported from another module. | ||
| 294 | struct ImportAnonymousSymbolEntry { | ||
| 295 | SegmentTag symbol_position; // in the exporting segment | ||
| 296 | u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable | ||
| 297 | |||
| 298 | static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset; | ||
| 299 | }; | ||
| 300 | ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8); | ||
| 301 | |||
| 302 | /// Information of a imported module and symbols imported from it. | ||
| 303 | struct ImportModuleEntry { | ||
| 304 | u32_le name_offset; // pointing to a substring in ImportStrings | ||
| 305 | u32_le import_indexed_symbol_table_offset; // pointing to a subtable in | ||
| 306 | // ImportIndexedSymbolTable | ||
| 307 | u32_le import_indexed_symbol_num; | ||
| 308 | u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in | ||
| 309 | // ImportAnonymousSymbolTable | ||
| 310 | u32_le import_anonymous_symbol_num; | ||
| 311 | |||
| 312 | static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset; | ||
| 313 | |||
| 314 | void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) { | ||
| 315 | Memory::ReadBlock(import_indexed_symbol_table_offset + | ||
| 316 | index * sizeof(ImportIndexedSymbolEntry), | ||
| 317 | &entry, sizeof(ImportIndexedSymbolEntry)); | ||
| 318 | } | ||
| 319 | |||
| 320 | void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) { | ||
| 321 | Memory::ReadBlock(import_anonymous_symbol_table_offset + | ||
| 322 | index * sizeof(ImportAnonymousSymbolEntry), | ||
| 323 | &entry, sizeof(ImportAnonymousSymbolEntry)); | ||
| 324 | } | ||
| 325 | }; | ||
| 326 | ASSERT_CRO_STRUCT(ImportModuleEntry, 20); | ||
| 327 | |||
| 328 | enum class RelocationType : u8 { | ||
| 329 | Nothing = 0, | ||
| 330 | AbsoluteAddress = 2, | ||
| 331 | RelativeAddress = 3, | ||
| 332 | ThumbBranch = 10, | ||
| 333 | ArmBranch = 28, | ||
| 334 | ModifyArmBranch = 29, | ||
| 335 | AbsoluteAddress2 = 38, | ||
| 336 | AlignedRelativeAddress = 42, | ||
| 337 | }; | ||
| 338 | |||
| 339 | struct RelocationEntry { | ||
| 340 | SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static | ||
| 341 | // module segment as a StaticRelocationEntry | ||
| 342 | RelocationType type; | ||
| 343 | u8 is_batch_end; | ||
| 344 | u8 is_batch_resolved; // set at a batch beginning if the batch is resolved | ||
| 345 | INSERT_PADDING_BYTES(1); | ||
| 346 | u32_le addend; | ||
| 347 | }; | ||
| 348 | |||
| 349 | /// Identifies a normal cross-module relocation. | ||
| 350 | struct ExternalRelocationEntry : RelocationEntry { | ||
| 351 | static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset; | ||
| 352 | }; | ||
| 353 | ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12); | ||
| 354 | |||
| 355 | /// Identifies a special static relocation (no game is known using this). | ||
| 356 | struct StaticRelocationEntry : RelocationEntry { | ||
| 357 | static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset; | ||
| 358 | }; | ||
| 359 | ASSERT_CRO_STRUCT(StaticRelocationEntry, 12); | ||
| 360 | |||
| 361 | /// Identifies a in-module relocation. | ||
| 362 | struct InternalRelocationEntry { | ||
| 363 | SegmentTag target_position; // to self's segment | ||
| 364 | RelocationType type; | ||
| 365 | u8 symbol_segment; | ||
| 366 | INSERT_PADDING_BYTES(2); | ||
| 367 | u32_le addend; | ||
| 368 | |||
| 369 | static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset; | ||
| 370 | }; | ||
| 371 | ASSERT_CRO_STRUCT(InternalRelocationEntry, 12); | ||
| 372 | |||
| 373 | /// Identifies a special static anonymous symbol (no game is known using this). | ||
| 374 | struct StaticAnonymousSymbolEntry { | ||
| 375 | SegmentTag symbol_position; // to self's segment | ||
| 376 | u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable | ||
| 377 | |||
| 378 | static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset; | ||
| 379 | }; | ||
| 380 | ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8); | ||
| 381 | |||
| 382 | /** | ||
| 383 | * Entry size of each table, from Code to StaticRelocationTable. | ||
| 384 | * Byte string contents (such as Code) are treated with entries of size 1. | ||
| 385 | * This is used for verifying the size of each table and calculating the fix end. | ||
| 386 | */ | ||
| 387 | static const std::array<int, 17> ENTRY_SIZE; | ||
| 388 | |||
| 389 | /// The offset field of the table where to crop for each fix level | ||
| 390 | static const std::array<HeaderField, 4> FIX_BARRIERS; | ||
| 391 | |||
| 392 | static constexpr u32 MAGIC_CRO0 = 0x304F5243; | ||
| 393 | static constexpr u32 MAGIC_FIXD = 0x44584946; | ||
| 394 | |||
| 395 | VAddr Field(HeaderField field) const { | ||
| 396 | return module_address + CRO_HASH_SIZE + field * 4; | ||
| 397 | } | ||
| 398 | |||
| 399 | u32 GetField(HeaderField field) const { | ||
| 400 | return Memory::Read32(Field(field)); | ||
| 401 | } | ||
| 402 | |||
| 403 | void SetField(HeaderField field, u32 value) { | ||
| 404 | Memory::Write32(Field(field), value); | ||
| 405 | } | ||
| 406 | |||
| 407 | /** | ||
| 408 | * Reads an entry in one of module tables. | ||
| 409 | * @param index index of the entry | ||
| 410 | * @param data where to put the read entry | ||
| 411 | * @note the entry type must have the static member TABLE_OFFSET_FIELD | ||
| 412 | * indicating which table the entry is in. | ||
| 413 | */ | ||
| 414 | template <typename T> | ||
| 415 | void GetEntry(std::size_t index, T& data) const { | ||
| 416 | Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), | ||
| 417 | &data, sizeof(T)); | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Writes an entry to one of module tables. | ||
| 422 | * @param index index of the entry | ||
| 423 | * @param data the entry data to write | ||
| 424 | * @note the entry type must have the static member TABLE_OFFSET_FIELD | ||
| 425 | * indicating which table the entry is in. | ||
| 426 | */ | ||
| 427 | template <typename T> | ||
| 428 | void SetEntry(std::size_t index, const T& data) { | ||
| 429 | Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), | ||
| 430 | &data, sizeof(T)); | ||
| 431 | } | ||
| 432 | |||
| 433 | /** | ||
| 434 | * Converts a segment tag to virtual address in this module. | ||
| 435 | * @param segment_tag the segment tag to convert | ||
| 436 | * @returns VAddr the virtual address the segment tag points to; 0 if invalid. | ||
| 437 | */ | ||
| 438 | VAddr SegmentTagToAddress(SegmentTag segment_tag) const; | ||
| 439 | |||
| 440 | VAddr NextModule() const { | ||
| 441 | return GetField(NextCRO); | ||
| 442 | } | ||
| 443 | |||
| 444 | VAddr PreviousModule() const { | ||
| 445 | return GetField(PreviousCRO); | ||
| 446 | } | ||
| 447 | |||
| 448 | void SetNextModule(VAddr next) { | ||
| 449 | SetField(NextCRO, next); | ||
| 450 | } | ||
| 451 | |||
| 452 | void SetPreviousModule(VAddr previous) { | ||
| 453 | SetField(PreviousCRO, previous); | ||
| 454 | } | ||
| 455 | |||
| 456 | /** | ||
| 457 | * A helper function iterating over all registered auto-link modules, including the static | ||
| 458 | * module. | ||
| 459 | * @param crs_address the virtual address of the static module | ||
| 460 | * @param func a function object to operate on a module. It accepts one parameter | ||
| 461 | * CROHelper and returns ResultVal<bool>. It should return true to continue the | ||
| 462 | * iteration, | ||
| 463 | * false to stop the iteration, or an error code (which will also stop the iteration). | ||
| 464 | * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration | ||
| 465 | * success, | ||
| 466 | * otherwise error code of the last iteration. | ||
| 467 | */ | ||
| 468 | template <typename FunctionObject> | ||
| 469 | static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) { | ||
| 470 | VAddr current = crs_address; | ||
| 471 | while (current != 0) { | ||
| 472 | CROHelper cro(current); | ||
| 473 | CASCADE_RESULT(bool next, func(cro)); | ||
| 474 | if (!next) | ||
| 475 | break; | ||
| 476 | current = cro.NextModule(); | ||
| 477 | } | ||
| 478 | return RESULT_SUCCESS; | ||
| 479 | } | ||
| 480 | |||
| 481 | /** | ||
| 482 | * Applies a relocation | ||
| 483 | * @param target_address where to apply the relocation | ||
| 484 | * @param relocation_type the type of the relocation | ||
| 485 | * @param addend address addend applied to the relocated symbol | ||
| 486 | * @param symbol_address the symbol address to be relocated with | ||
| 487 | * @param target_future_address the future address of the target. | ||
| 488 | * Usually equals to target_address, but will be different for a target in .data segment | ||
| 489 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 490 | */ | ||
| 491 | ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend, | ||
| 492 | u32 symbol_address, u32 target_future_address); | ||
| 493 | |||
| 494 | /** | ||
| 495 | * Clears a relocation to zero | ||
| 496 | * @param target_address where to apply the relocation | ||
| 497 | * @param relocation_type the type of the relocation | ||
| 498 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 499 | */ | ||
| 500 | ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type); | ||
| 501 | |||
| 502 | /** | ||
| 503 | * Applies or resets a batch of relocations | ||
| 504 | * @param batch the virtual address of the first relocation in the batch | ||
| 505 | * @param symbol_address the symbol address to be relocated with | ||
| 506 | * @param reset false to set the batch to resolved state, true to reset the batch to unresolved | ||
| 507 | * state | ||
| 508 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 509 | */ | ||
| 510 | ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false); | ||
| 511 | |||
| 512 | /** | ||
| 513 | * Finds an exported named symbol in this module. | ||
| 514 | * @param name the name of the symbol to find | ||
| 515 | * @return VAddr the virtual address of the symbol; 0 if not found. | ||
| 516 | */ | ||
| 517 | VAddr FindExportNamedSymbol(const std::string& name) const; | ||
| 518 | |||
| 519 | /** | ||
| 520 | * Rebases offsets in module header according to module address. | ||
| 521 | * @param cro_size the size of the CRO file | ||
| 522 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 523 | * code. | ||
| 524 | */ | ||
| 525 | ResultCode RebaseHeader(u32 cro_size); | ||
| 526 | |||
| 527 | /** | ||
| 528 | * Rebases offsets in segment table according to module address. | ||
| 529 | * @param cro_size the size of the CRO file | ||
| 530 | * @param data_segment_address the buffer address for .data segment | ||
| 531 | * @param data_segment_size the buffer size for .data segment | ||
| 532 | * @param bss_segment_address the buffer address for .bss segment | ||
| 533 | * @param bss_segment_size the buffer size for .bss segment | ||
| 534 | * @returns ResultVal<VAddr> with the virtual address of .data segment in CRO. | ||
| 535 | */ | ||
| 536 | ResultVal<VAddr> RebaseSegmentTable(u32 cro_size, VAddr data_segment_address, | ||
| 537 | u32 data_segment_size, VAddr bss_segment_address, | ||
| 538 | u32 bss_segment_size); | ||
| 539 | |||
| 540 | /** | ||
| 541 | * Rebases offsets in exported named symbol table according to module address. | ||
| 542 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 543 | * code. | ||
| 544 | */ | ||
| 545 | ResultCode RebaseExportNamedSymbolTable(); | ||
| 546 | |||
| 547 | /** | ||
| 548 | * Verifies indices in export tree table. | ||
| 549 | * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error | ||
| 550 | * code. | ||
| 551 | */ | ||
| 552 | ResultCode VerifyExportTreeTable() const; | ||
| 553 | |||
| 554 | /** | ||
| 555 | * Rebases offsets in exported module table according to module address. | ||
| 556 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 557 | * code. | ||
| 558 | */ | ||
| 559 | ResultCode RebaseImportModuleTable(); | ||
| 560 | |||
| 561 | /** | ||
| 562 | * Rebases offsets in imported named symbol table according to module address. | ||
| 563 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 564 | * code. | ||
| 565 | */ | ||
| 566 | ResultCode RebaseImportNamedSymbolTable(); | ||
| 567 | |||
| 568 | /** | ||
| 569 | * Rebases offsets in imported indexed symbol table according to module address. | ||
| 570 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 571 | * code. | ||
| 572 | */ | ||
| 573 | ResultCode RebaseImportIndexedSymbolTable(); | ||
| 574 | |||
| 575 | /** | ||
| 576 | * Rebases offsets in imported anonymous symbol table according to module address. | ||
| 577 | * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error | ||
| 578 | * code. | ||
| 579 | */ | ||
| 580 | ResultCode RebaseImportAnonymousSymbolTable(); | ||
| 581 | |||
| 582 | /** | ||
| 583 | * Gets the address of OnUnresolved function in this module. | ||
| 584 | * Used as the applied symbol for reset relocation. | ||
| 585 | * @returns the virtual address of OnUnresolved. 0 if not provided. | ||
| 586 | */ | ||
| 587 | VAddr GetOnUnresolvedAddress(); | ||
| 588 | |||
| 589 | /** | ||
| 590 | * Resets all external relocations to unresolved state. | ||
| 591 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 592 | */ | ||
| 593 | ResultCode ResetExternalRelocations(); | ||
| 594 | |||
| 595 | /** | ||
| 596 | * Clears all external relocations to zero. | ||
| 597 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 598 | */ | ||
| 599 | ResultCode ClearExternalRelocations(); | ||
| 600 | |||
| 601 | /** | ||
| 602 | * Applies all static anonymous symbol to the static module. | ||
| 603 | * @param crs_address the virtual address of the static module | ||
| 604 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 605 | */ | ||
| 606 | ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address); | ||
| 607 | |||
| 608 | /** | ||
| 609 | * Applies all internal relocations to the module itself. | ||
| 610 | * @param old_data_segment_address the virtual address of data segment in CRO buffer | ||
| 611 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 612 | */ | ||
| 613 | ResultCode ApplyInternalRelocations(u32 old_data_segment_address); | ||
| 614 | |||
| 615 | /** | ||
| 616 | * Clears all internal relocations to zero. | ||
| 617 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 618 | */ | ||
| 619 | ResultCode ClearInternalRelocations(); | ||
| 620 | |||
| 621 | /// Unrebases offsets in imported anonymous symbol table | ||
| 622 | void UnrebaseImportAnonymousSymbolTable(); | ||
| 623 | |||
| 624 | /// Unrebases offsets in imported indexed symbol table | ||
| 625 | void UnrebaseImportIndexedSymbolTable(); | ||
| 626 | |||
| 627 | /// Unrebases offsets in imported named symbol table | ||
| 628 | void UnrebaseImportNamedSymbolTable(); | ||
| 629 | |||
| 630 | /// Unrebases offsets in imported module table | ||
| 631 | void UnrebaseImportModuleTable(); | ||
| 632 | |||
| 633 | /// Unrebases offsets in exported named symbol table | ||
| 634 | void UnrebaseExportNamedSymbolTable(); | ||
| 635 | |||
| 636 | /// Unrebases offsets in segment table | ||
| 637 | void UnrebaseSegmentTable(); | ||
| 638 | |||
| 639 | /// Unrebases offsets in module header | ||
| 640 | void UnrebaseHeader(); | ||
| 641 | |||
| 642 | /** | ||
| 643 | * Looks up all imported named symbols of this module in all registered auto-link modules, and | ||
| 644 | * resolves them if found. | ||
| 645 | * @param crs_address the virtual address of the static module | ||
| 646 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 647 | */ | ||
| 648 | ResultCode ApplyImportNamedSymbol(VAddr crs_address); | ||
| 649 | |||
| 650 | /** | ||
| 651 | * Resets all imported named symbols of this module to unresolved state. | ||
| 652 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 653 | */ | ||
| 654 | ResultCode ResetImportNamedSymbol(); | ||
| 655 | |||
| 656 | /** | ||
| 657 | * Resets all imported indexed symbols of this module to unresolved state. | ||
| 658 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 659 | */ | ||
| 660 | ResultCode ResetImportIndexedSymbol(); | ||
| 661 | |||
| 662 | /** | ||
| 663 | * Resets all imported anonymous symbols of this module to unresolved state. | ||
| 664 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 665 | */ | ||
| 666 | ResultCode ResetImportAnonymousSymbol(); | ||
| 667 | |||
| 668 | /** | ||
| 669 | * Finds registered auto-link modules that this module imports, and resolves indexed and | ||
| 670 | * anonymous symbols exported by them. | ||
| 671 | * @param crs_address the virtual address of the static module | ||
| 672 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 673 | */ | ||
| 674 | ResultCode ApplyModuleImport(VAddr crs_address); | ||
| 675 | |||
| 676 | /** | ||
| 677 | * Resolves target module's imported named symbols that exported by this module. | ||
| 678 | * @param target the module to resolve. | ||
| 679 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 680 | */ | ||
| 681 | ResultCode ApplyExportNamedSymbol(CROHelper target); | ||
| 682 | |||
| 683 | /** | ||
| 684 | * Resets target's named symbols imported from this module to unresolved state. | ||
| 685 | * @param target the module to reset. | ||
| 686 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 687 | */ | ||
| 688 | ResultCode ResetExportNamedSymbol(CROHelper target); | ||
| 689 | |||
| 690 | /** | ||
| 691 | * Resolves imported indexed and anonymous symbols in the target module which imports this | ||
| 692 | * module. | ||
| 693 | * @param target the module to resolve. | ||
| 694 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 695 | */ | ||
| 696 | ResultCode ApplyModuleExport(CROHelper target); | ||
| 697 | |||
| 698 | /** | ||
| 699 | * Resets target's indexed and anonymous symbol imported from this module to unresolved state. | ||
| 700 | * @param target the module to reset. | ||
| 701 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 702 | */ | ||
| 703 | ResultCode ResetModuleExport(CROHelper target); | ||
| 704 | |||
| 705 | /** | ||
| 706 | * Resolves the exit function in this module | ||
| 707 | * @param crs_address the virtual address of the static module. | ||
| 708 | * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. | ||
| 709 | */ | ||
| 710 | ResultCode ApplyExitRelocations(VAddr crs_address); | ||
| 711 | }; | ||
| 712 | |||
| 713 | } // namespace LDR | ||
| 714 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp deleted file mode 100644 index 7255ea026..000000000 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ /dev/null | |||
| @@ -1,718 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/alignment.h" | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/arm/arm_interface.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/hle/ipc_helpers.h" | ||
| 11 | #include "core/hle/kernel/process.h" | ||
| 12 | #include "core/hle/kernel/vm_manager.h" | ||
| 13 | #include "core/hle/service/ldr_ro/cro_helper.h" | ||
| 14 | #include "core/hle/service/ldr_ro/ldr_ro.h" | ||
| 15 | #include "core/hle/service/ldr_ro/memory_synchronizer.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace LDR { | ||
| 19 | |||
| 20 | static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9 | ||
| 21 | ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal, | ||
| 22 | ErrorLevel::Permanent); | ||
| 23 | static const ResultCode ERROR_NOT_INITIALIZED = // 0xD9612FF8 | ||
| 24 | ResultCode(ErrorDescription::NotInitialized, ErrorModule::RO, ErrorSummary::Internal, | ||
| 25 | ErrorLevel::Permanent); | ||
| 26 | static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F | ||
| 27 | ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, | ||
| 28 | ErrorLevel::Usage); | ||
| 29 | static const ResultCode ERROR_MISALIGNED_ADDRESS = // 0xD9012FF1 | ||
| 30 | ResultCode(ErrorDescription::MisalignedAddress, ErrorModule::RO, ErrorSummary::WrongArgument, | ||
| 31 | ErrorLevel::Permanent); | ||
| 32 | static const ResultCode ERROR_MISALIGNED_SIZE = // 0xD9012FF2 | ||
| 33 | ResultCode(ErrorDescription::MisalignedSize, ErrorModule::RO, ErrorSummary::WrongArgument, | ||
| 34 | ErrorLevel::Permanent); | ||
| 35 | static const ResultCode ERROR_ILLEGAL_ADDRESS = // 0xE1612C0F | ||
| 36 | ResultCode(static_cast<ErrorDescription>(15), ErrorModule::RO, ErrorSummary::Internal, | ||
| 37 | ErrorLevel::Usage); | ||
| 38 | static const ResultCode ERROR_INVALID_MEMORY_STATE = // 0xD8A12C08 | ||
| 39 | ResultCode(static_cast<ErrorDescription>(8), ErrorModule::RO, ErrorSummary::InvalidState, | ||
| 40 | ErrorLevel::Permanent); | ||
| 41 | static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D | ||
| 42 | ResultCode(static_cast<ErrorDescription>(13), ErrorModule::RO, ErrorSummary::InvalidState, | ||
| 43 | ErrorLevel::Permanent); | ||
| 44 | |||
| 45 | static MemorySynchronizer memory_synchronizer; | ||
| 46 | |||
| 47 | // TODO(wwylele): this should be in the per-client storage when we implement multi-process | ||
| 48 | static VAddr loaded_crs; ///< the virtual address of the static module | ||
| 49 | |||
| 50 | static bool VerifyBufferState(VAddr buffer_ptr, u32 size) { | ||
| 51 | auto vma = Kernel::g_current_process->vm_manager.FindVMA(buffer_ptr); | ||
| 52 | return vma != Kernel::g_current_process->vm_manager.vma_map.end() && | ||
| 53 | vma->second.base + vma->second.size >= buffer_ptr + size && | ||
| 54 | vma->second.permissions == Kernel::VMAPermission::ReadWrite && | ||
| 55 | vma->second.meminfo_state == Kernel::MemoryState::Private; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * LDR_RO::Initialize service function | ||
| 60 | * Inputs: | ||
| 61 | * 0 : 0x000100C2 | ||
| 62 | * 1 : CRS buffer pointer | ||
| 63 | * 2 : CRS Size | ||
| 64 | * 3 : Process memory address where the CRS will be mapped | ||
| 65 | * 4 : handle translation descriptor (zero) | ||
| 66 | * 5 : KProcess handle | ||
| 67 | * Outputs: | ||
| 68 | * 0 : Return header | ||
| 69 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 70 | */ | ||
| 71 | static void Initialize(Interface* self) { | ||
| 72 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 3, 2); | ||
| 73 | VAddr crs_buffer_ptr = rp.Pop<u32>(); | ||
| 74 | u32 crs_size = rp.Pop<u32>(); | ||
| 75 | VAddr crs_address = rp.Pop<u32>(); | ||
| 76 | // TODO (wwylele): RO service checks the descriptor here and return error 0xD9001830 for | ||
| 77 | // incorrect descriptor. This error return should be probably built in IPC::RequestParser. | ||
| 78 | // All other service functions below have the same issue. | ||
| 79 | Kernel::Handle process = rp.PopHandle(); | ||
| 80 | |||
| 81 | LOG_DEBUG(Service_LDR, | ||
| 82 | "called, crs_buffer_ptr=0x%08X, crs_address=0x%08X, crs_size=0x%X, process=0x%08X", | ||
| 83 | crs_buffer_ptr, crs_address, crs_size, process); | ||
| 84 | |||
| 85 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 86 | |||
| 87 | if (loaded_crs != 0) { | ||
| 88 | LOG_ERROR(Service_LDR, "Already initialized"); | ||
| 89 | rb.Push(ERROR_ALREADY_INITIALIZED); | ||
| 90 | return; | ||
| 91 | } | ||
| 92 | |||
| 93 | if (crs_size < CRO_HEADER_SIZE) { | ||
| 94 | LOG_ERROR(Service_LDR, "CRS is too small"); | ||
| 95 | rb.Push(ERROR_BUFFER_TOO_SMALL); | ||
| 96 | return; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (crs_buffer_ptr & Memory::PAGE_MASK) { | ||
| 100 | LOG_ERROR(Service_LDR, "CRS original address is not aligned"); | ||
| 101 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (crs_address & Memory::PAGE_MASK) { | ||
| 106 | LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); | ||
| 107 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (crs_size & Memory::PAGE_MASK) { | ||
| 112 | LOG_ERROR(Service_LDR, "CRS size is not aligned"); | ||
| 113 | rb.Push(ERROR_MISALIGNED_SIZE); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | if (!VerifyBufferState(crs_buffer_ptr, crs_size)) { | ||
| 118 | LOG_ERROR(Service_LDR, "CRS original buffer is in invalid state"); | ||
| 119 | rb.Push(ERROR_INVALID_MEMORY_STATE); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | |||
| 123 | if (crs_address < Memory::PROCESS_IMAGE_VADDR || | ||
| 124 | crs_address + crs_size > Memory::PROCESS_IMAGE_VADDR_END) { | ||
| 125 | LOG_ERROR(Service_LDR, "CRS mapping address is not in the process image region"); | ||
| 126 | rb.Push(ERROR_ILLEGAL_ADDRESS); | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | ResultCode result = RESULT_SUCCESS; | ||
| 131 | |||
| 132 | if (crs_buffer_ptr != crs_address) { | ||
| 133 | // TODO(wwylele): should be memory aliasing | ||
| 134 | std::shared_ptr<std::vector<u8>> crs_mem = std::make_shared<std::vector<u8>>(crs_size); | ||
| 135 | Memory::ReadBlock(crs_buffer_ptr, crs_mem->data(), crs_size); | ||
| 136 | result = Kernel::g_current_process->vm_manager | ||
| 137 | .MapMemoryBlock(crs_address, crs_mem, 0, crs_size, Kernel::MemoryState::Code) | ||
| 138 | .Code(); | ||
| 139 | if (result.IsError()) { | ||
| 140 | LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); | ||
| 141 | rb.Push(result); | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | |||
| 145 | result = Kernel::g_current_process->vm_manager.ReprotectRange(crs_address, crs_size, | ||
| 146 | Kernel::VMAPermission::Read); | ||
| 147 | if (result.IsError()) { | ||
| 148 | LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); | ||
| 149 | rb.Push(result); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | |||
| 153 | memory_synchronizer.AddMemoryBlock(crs_address, crs_buffer_ptr, crs_size); | ||
| 154 | } else { | ||
| 155 | // Do nothing if buffer_ptr == address | ||
| 156 | // TODO(wwylele): verify this behaviour. This is only seen in the web browser app, | ||
| 157 | // and the actual behaviour is unclear. "Do nothing" is probably an incorrect implement. | ||
| 158 | // There is also a chance that another issue causes the app passing wrong arguments. | ||
| 159 | LOG_WARNING(Service_LDR, "crs_buffer_ptr == crs_address (0x%08X)", crs_address); | ||
| 160 | } | ||
| 161 | |||
| 162 | CROHelper crs(crs_address); | ||
| 163 | crs.InitCRS(); | ||
| 164 | |||
| 165 | result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true); | ||
| 166 | if (result.IsError()) { | ||
| 167 | LOG_ERROR(Service_LDR, "Error rebasing CRS 0x%08X", result.raw); | ||
| 168 | rb.Push(result); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 172 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 173 | |||
| 174 | loaded_crs = crs_address; | ||
| 175 | |||
| 176 | rb.Push(RESULT_SUCCESS); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * LDR_RO::LoadCRR service function | ||
| 181 | * Inputs: | ||
| 182 | * 0 : 0x00020082 | ||
| 183 | * 1 : CRR buffer pointer | ||
| 184 | * 2 : CRR Size | ||
| 185 | * 3 : handle translation descriptor (zero) | ||
| 186 | * 4 : KProcess handle | ||
| 187 | * Outputs: | ||
| 188 | * 0 : Return header | ||
| 189 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 190 | */ | ||
| 191 | static void LoadCRR(Interface* self) { | ||
| 192 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 2); | ||
| 193 | VAddr crr_buffer_ptr = rp.Pop<u32>(); | ||
| 194 | u32 crr_size = rp.Pop<u32>(); | ||
| 195 | Kernel::Handle process = rp.PopHandle(); | ||
| 196 | |||
| 197 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 198 | rb.Push(RESULT_SUCCESS); | ||
| 199 | |||
| 200 | LOG_WARNING(Service_LDR, | ||
| 201 | "(STUBBED) called, crr_buffer_ptr=0x%08X, crr_size=0x%08X, process=0x%08X", | ||
| 202 | crr_buffer_ptr, crr_size, process); | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * LDR_RO::UnloadCRR service function | ||
| 207 | * Inputs: | ||
| 208 | * 0 : 0x00030042 | ||
| 209 | * 1 : CRR buffer pointer | ||
| 210 | * 2 : handle translation descriptor (zero) | ||
| 211 | * 3 : KProcess handle | ||
| 212 | * Outputs: | ||
| 213 | * 0 : Return header | ||
| 214 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 215 | */ | ||
| 216 | static void UnloadCRR(Interface* self) { | ||
| 217 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 2); | ||
| 218 | u32 crr_buffer_ptr = rp.Pop<u32>(); | ||
| 219 | Kernel::Handle process = rp.PopHandle(); | ||
| 220 | |||
| 221 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 222 | rb.Push(RESULT_SUCCESS); | ||
| 223 | |||
| 224 | LOG_WARNING(Service_LDR, "(STUBBED) called, crr_buffer_ptr=0x%08X, process=0x%08X", | ||
| 225 | crr_buffer_ptr, process); | ||
| 226 | } | ||
| 227 | |||
| 228 | /** | ||
| 229 | * LDR_RO::LoadCRO service function | ||
| 230 | * Inputs: | ||
| 231 | * 0 : 0x000402C2 (old) / 0x000902C2 (new) | ||
| 232 | * 1 : CRO buffer pointer | ||
| 233 | * 2 : memory address where the CRO will be mapped | ||
| 234 | * 3 : CRO Size | ||
| 235 | * 4 : .data segment buffer pointer | ||
| 236 | * 5 : must be zero | ||
| 237 | * 6 : .data segment buffer size | ||
| 238 | * 7 : .bss segment buffer pointer | ||
| 239 | * 8 : .bss segment buffer size | ||
| 240 | * 9 : (bool) register CRO as auto-link module | ||
| 241 | * 10 : fix level | ||
| 242 | * 11 : CRR address (zero if use loaded CRR) | ||
| 243 | * 12 : handle translation descriptor (zero) | ||
| 244 | * 13 : KProcess handle | ||
| 245 | * Outputs: | ||
| 246 | * 0 : Return header | ||
| 247 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 248 | * 2 : CRO fixed size | ||
| 249 | * Note: | ||
| 250 | * This service function has two versions. The function defined here is a | ||
| 251 | * unified one of two, with an additional parameter link_on_load_bug_fix. | ||
| 252 | * There is a dispatcher template below. | ||
| 253 | */ | ||
| 254 | static void LoadCRO(Interface* self, bool link_on_load_bug_fix) { | ||
| 255 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), link_on_load_bug_fix ? 0x09 : 0x04, 11, 2); | ||
| 256 | VAddr cro_buffer_ptr = rp.Pop<u32>(); | ||
| 257 | VAddr cro_address = rp.Pop<u32>(); | ||
| 258 | u32 cro_size = rp.Pop<u32>(); | ||
| 259 | VAddr data_segment_address = rp.Pop<u32>(); | ||
| 260 | u32 zero = rp.Pop<u32>(); | ||
| 261 | u32 data_segment_size = rp.Pop<u32>(); | ||
| 262 | u32 bss_segment_address = rp.Pop<u32>(); | ||
| 263 | u32 bss_segment_size = rp.Pop<u32>(); | ||
| 264 | bool auto_link = rp.Pop<bool>(); | ||
| 265 | u32 fix_level = rp.Pop<u32>(); | ||
| 266 | VAddr crr_address = rp.Pop<u32>(); | ||
| 267 | Kernel::Handle process = rp.PopHandle(); | ||
| 268 | |||
| 269 | LOG_DEBUG(Service_LDR, "called (%s), cro_buffer_ptr=0x%08X, cro_address=0x%08X, cro_size=0x%X, " | ||
| 270 | "data_segment_address=0x%08X, zero=%d, data_segment_size=0x%X, " | ||
| 271 | "bss_segment_address=0x%08X, bss_segment_size=0x%X, auto_link=%s, " | ||
| 272 | "fix_level=%d, crr_address=0x%08X, process=0x%08X", | ||
| 273 | link_on_load_bug_fix ? "new" : "old", cro_buffer_ptr, cro_address, cro_size, | ||
| 274 | data_segment_address, zero, data_segment_size, bss_segment_address, bss_segment_size, | ||
| 275 | auto_link ? "true" : "false", fix_level, crr_address, process); | ||
| 276 | |||
| 277 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 278 | |||
| 279 | if (loaded_crs == 0) { | ||
| 280 | LOG_ERROR(Service_LDR, "Not initialized"); | ||
| 281 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 282 | rb.Push<u32>(0); | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | |||
| 286 | if (cro_size < CRO_HEADER_SIZE) { | ||
| 287 | LOG_ERROR(Service_LDR, "CRO too small"); | ||
| 288 | rb.Push(ERROR_BUFFER_TOO_SMALL); | ||
| 289 | rb.Push<u32>(0); | ||
| 290 | return; | ||
| 291 | } | ||
| 292 | |||
| 293 | if (cro_buffer_ptr & Memory::PAGE_MASK) { | ||
| 294 | LOG_ERROR(Service_LDR, "CRO original address is not aligned"); | ||
| 295 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 296 | rb.Push<u32>(0); | ||
| 297 | return; | ||
| 298 | } | ||
| 299 | |||
| 300 | if (cro_address & Memory::PAGE_MASK) { | ||
| 301 | LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); | ||
| 302 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 303 | rb.Push<u32>(0); | ||
| 304 | return; | ||
| 305 | } | ||
| 306 | |||
| 307 | if (cro_size & Memory::PAGE_MASK) { | ||
| 308 | LOG_ERROR(Service_LDR, "CRO size is not aligned"); | ||
| 309 | rb.Push(ERROR_MISALIGNED_SIZE); | ||
| 310 | rb.Push<u32>(0); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | if (!VerifyBufferState(cro_buffer_ptr, cro_size)) { | ||
| 315 | LOG_ERROR(Service_LDR, "CRO original buffer is in invalid state"); | ||
| 316 | rb.Push(ERROR_INVALID_MEMORY_STATE); | ||
| 317 | rb.Push<u32>(0); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (cro_address < Memory::PROCESS_IMAGE_VADDR || | ||
| 322 | cro_address + cro_size > Memory::PROCESS_IMAGE_VADDR_END) { | ||
| 323 | LOG_ERROR(Service_LDR, "CRO mapping address is not in the process image region"); | ||
| 324 | rb.Push(ERROR_ILLEGAL_ADDRESS); | ||
| 325 | rb.Push<u32>(0); | ||
| 326 | return; | ||
| 327 | } | ||
| 328 | |||
| 329 | if (zero) { | ||
| 330 | LOG_ERROR(Service_LDR, "Zero is not zero %d", zero); | ||
| 331 | rb.Push(ResultCode(static_cast<ErrorDescription>(29), ErrorModule::RO, | ||
| 332 | ErrorSummary::Internal, ErrorLevel::Usage)); | ||
| 333 | rb.Push<u32>(0); | ||
| 334 | return; | ||
| 335 | } | ||
| 336 | |||
| 337 | ResultCode result = RESULT_SUCCESS; | ||
| 338 | |||
| 339 | if (cro_buffer_ptr != cro_address) { | ||
| 340 | // TODO(wwylele): should be memory aliasing | ||
| 341 | std::shared_ptr<std::vector<u8>> cro_mem = std::make_shared<std::vector<u8>>(cro_size); | ||
| 342 | Memory::ReadBlock(cro_buffer_ptr, cro_mem->data(), cro_size); | ||
| 343 | result = Kernel::g_current_process->vm_manager | ||
| 344 | .MapMemoryBlock(cro_address, cro_mem, 0, cro_size, Kernel::MemoryState::Code) | ||
| 345 | .Code(); | ||
| 346 | if (result.IsError()) { | ||
| 347 | LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw); | ||
| 348 | rb.Push(result); | ||
| 349 | rb.Push<u32>(0); | ||
| 350 | return; | ||
| 351 | } | ||
| 352 | |||
| 353 | result = Kernel::g_current_process->vm_manager.ReprotectRange(cro_address, cro_size, | ||
| 354 | Kernel::VMAPermission::Read); | ||
| 355 | if (result.IsError()) { | ||
| 356 | LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); | ||
| 357 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); | ||
| 358 | rb.Push(result); | ||
| 359 | rb.Push<u32>(0); | ||
| 360 | return; | ||
| 361 | } | ||
| 362 | |||
| 363 | memory_synchronizer.AddMemoryBlock(cro_address, cro_buffer_ptr, cro_size); | ||
| 364 | } else { | ||
| 365 | // Do nothing if buffer_ptr == address | ||
| 366 | // TODO(wwylele): verify this behaviour. | ||
| 367 | // This is derived from the case of LoadCRS with buffer_ptr==address, | ||
| 368 | // and is never seen in any game. "Do nothing" is probably an incorrect implement. | ||
| 369 | // There is also a chance that this case is just prohibited. | ||
| 370 | LOG_WARNING(Service_LDR, "cro_buffer_ptr == cro_address (0x%08X)", cro_address); | ||
| 371 | } | ||
| 372 | |||
| 373 | CROHelper cro(cro_address); | ||
| 374 | |||
| 375 | result = cro.VerifyHash(cro_size, crr_address); | ||
| 376 | if (result.IsError()) { | ||
| 377 | LOG_ERROR(Service_LDR, "Error verifying CRO in CRR %08X", result.raw); | ||
| 378 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); | ||
| 379 | rb.Push(result); | ||
| 380 | rb.Push<u32>(0); | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | |||
| 384 | result = cro.Rebase(loaded_crs, cro_size, data_segment_address, data_segment_size, | ||
| 385 | bss_segment_address, bss_segment_size, false); | ||
| 386 | if (result.IsError()) { | ||
| 387 | LOG_ERROR(Service_LDR, "Error rebasing CRO %08X", result.raw); | ||
| 388 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); | ||
| 389 | rb.Push(result); | ||
| 390 | rb.Push<u32>(0); | ||
| 391 | return; | ||
| 392 | } | ||
| 393 | |||
| 394 | result = cro.Link(loaded_crs, link_on_load_bug_fix); | ||
| 395 | if (result.IsError()) { | ||
| 396 | LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); | ||
| 397 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); | ||
| 398 | rb.Push(result); | ||
| 399 | rb.Push<u32>(0); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | cro.Register(loaded_crs, auto_link); | ||
| 404 | |||
| 405 | u32 fix_size = cro.Fix(fix_level); | ||
| 406 | |||
| 407 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 408 | |||
| 409 | // TODO(wwylele): verify the behaviour when buffer_ptr == address | ||
| 410 | if (cro_buffer_ptr != cro_address) { | ||
| 411 | if (fix_size != cro_size) { | ||
| 412 | result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address + fix_size, | ||
| 413 | cro_size - fix_size); | ||
| 414 | if (result.IsError()) { | ||
| 415 | LOG_ERROR(Service_LDR, "Error unmapping memory block %08X", result.raw); | ||
| 416 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size); | ||
| 417 | rb.Push(result); | ||
| 418 | rb.Push<u32>(0); | ||
| 419 | return; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | // Changes the block size | ||
| 424 | memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size); | ||
| 425 | } | ||
| 426 | |||
| 427 | VAddr exe_begin; | ||
| 428 | u32 exe_size; | ||
| 429 | std::tie(exe_begin, exe_size) = cro.GetExecutablePages(); | ||
| 430 | if (exe_begin) { | ||
| 431 | result = Kernel::g_current_process->vm_manager.ReprotectRange( | ||
| 432 | exe_begin, exe_size, Kernel::VMAPermission::ReadExecute); | ||
| 433 | if (result.IsError()) { | ||
| 434 | LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw); | ||
| 435 | Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fix_size); | ||
| 436 | rb.Push(result); | ||
| 437 | rb.Push<u32>(0); | ||
| 438 | return; | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | Core::CPU().ClearInstructionCache(); | ||
| 443 | |||
| 444 | LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(), | ||
| 445 | cro_address, cro_address + fix_size); | ||
| 446 | |||
| 447 | rb.Push(RESULT_SUCCESS, fix_size); | ||
| 448 | } | ||
| 449 | |||
| 450 | template <bool link_on_load_bug_fix> | ||
| 451 | static void LoadCRO(Interface* self) { | ||
| 452 | LoadCRO(self, link_on_load_bug_fix); | ||
| 453 | } | ||
| 454 | |||
| 455 | /** | ||
| 456 | * LDR_RO::UnloadCRO service function | ||
| 457 | * Inputs: | ||
| 458 | * 0 : 0x000500C2 | ||
| 459 | * 1 : mapped CRO pointer | ||
| 460 | * 2 : zero? (RO service doesn't care) | ||
| 461 | * 3 : original CRO pointer | ||
| 462 | * 4 : handle translation descriptor (zero) | ||
| 463 | * 5 : KProcess handle | ||
| 464 | * Outputs: | ||
| 465 | * 0 : Return header | ||
| 466 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 467 | */ | ||
| 468 | static void UnloadCRO(Interface* self) { | ||
| 469 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 3, 2); | ||
| 470 | VAddr cro_address = rp.Pop<u32>(); | ||
| 471 | u32 zero = rp.Pop<u32>(); | ||
| 472 | VAddr cro_buffer_ptr = rp.Pop<u32>(); | ||
| 473 | Kernel::Handle process = rp.PopHandle(); | ||
| 474 | |||
| 475 | LOG_DEBUG(Service_LDR, | ||
| 476 | "called, cro_address=0x%08X, zero=%d, cro_buffer_ptr=0x%08X, process=0x%08X", | ||
| 477 | cro_address, zero, cro_buffer_ptr, process); | ||
| 478 | |||
| 479 | CROHelper cro(cro_address); | ||
| 480 | |||
| 481 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 482 | |||
| 483 | if (loaded_crs == 0) { | ||
| 484 | LOG_ERROR(Service_LDR, "Not initialized"); | ||
| 485 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | |||
| 489 | if (cro_address & Memory::PAGE_MASK) { | ||
| 490 | LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||
| 491 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 492 | return; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (!cro.IsLoaded()) { | ||
| 496 | LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); | ||
| 497 | rb.Push(ERROR_NOT_LOADED); | ||
| 498 | return; | ||
| 499 | } | ||
| 500 | |||
| 501 | LOG_INFO(Service_LDR, "Unloading CRO \"%s\"", cro.ModuleName().data()); | ||
| 502 | |||
| 503 | u32 fixed_size = cro.GetFixedSize(); | ||
| 504 | |||
| 505 | cro.Unregister(loaded_crs); | ||
| 506 | |||
| 507 | ResultCode result = cro.Unlink(loaded_crs); | ||
| 508 | if (result.IsError()) { | ||
| 509 | LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); | ||
| 510 | rb.Push(result); | ||
| 511 | return; | ||
| 512 | } | ||
| 513 | |||
| 514 | // If the module is not fixed, clears all external/internal relocations | ||
| 515 | // to restore the state before loading, so that it can be loaded again(?) | ||
| 516 | if (!cro.IsFixed()) { | ||
| 517 | result = cro.ClearRelocations(); | ||
| 518 | if (result.IsError()) { | ||
| 519 | LOG_ERROR(Service_LDR, "Error clearing relocations %08X", result.raw); | ||
| 520 | rb.Push(result); | ||
| 521 | return; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | cro.Unrebase(false); | ||
| 526 | |||
| 527 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 528 | |||
| 529 | // TODO(wwylele): verify the behaviour when buffer_ptr == address | ||
| 530 | if (cro_address != cro_buffer_ptr) { | ||
| 531 | result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fixed_size); | ||
| 532 | if (result.IsError()) { | ||
| 533 | LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw); | ||
| 534 | } | ||
| 535 | memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr); | ||
| 536 | } | ||
| 537 | |||
| 538 | Core::CPU().ClearInstructionCache(); | ||
| 539 | |||
| 540 | rb.Push(result); | ||
| 541 | } | ||
| 542 | |||
| 543 | /** | ||
| 544 | * LDR_RO::LinkCRO service function | ||
| 545 | * Inputs: | ||
| 546 | * 0 : 0x00060042 | ||
| 547 | * 1 : mapped CRO pointer | ||
| 548 | * 2 : handle translation descriptor (zero) | ||
| 549 | * 3 : KProcess handle | ||
| 550 | * Outputs: | ||
| 551 | * 0 : Return header | ||
| 552 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 553 | */ | ||
| 554 | static void LinkCRO(Interface* self) { | ||
| 555 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 2); | ||
| 556 | VAddr cro_address = rp.Pop<u32>(); | ||
| 557 | Kernel::Handle process = rp.PopHandle(); | ||
| 558 | |||
| 559 | LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process); | ||
| 560 | |||
| 561 | CROHelper cro(cro_address); | ||
| 562 | |||
| 563 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 564 | |||
| 565 | if (loaded_crs == 0) { | ||
| 566 | LOG_ERROR(Service_LDR, "Not initialized"); | ||
| 567 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (cro_address & Memory::PAGE_MASK) { | ||
| 572 | LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||
| 573 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 574 | return; | ||
| 575 | } | ||
| 576 | |||
| 577 | if (!cro.IsLoaded()) { | ||
| 578 | LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); | ||
| 579 | rb.Push(ERROR_NOT_LOADED); | ||
| 580 | return; | ||
| 581 | } | ||
| 582 | |||
| 583 | LOG_INFO(Service_LDR, "Linking CRO \"%s\"", cro.ModuleName().data()); | ||
| 584 | |||
| 585 | ResultCode result = cro.Link(loaded_crs, false); | ||
| 586 | if (result.IsError()) { | ||
| 587 | LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw); | ||
| 588 | } | ||
| 589 | |||
| 590 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 591 | Core::CPU().ClearInstructionCache(); | ||
| 592 | |||
| 593 | rb.Push(result); | ||
| 594 | } | ||
| 595 | |||
| 596 | /** | ||
| 597 | * LDR_RO::UnlinkCRO service function | ||
| 598 | * Inputs: | ||
| 599 | * 0 : 0x00070042 | ||
| 600 | * 1 : mapped CRO pointer | ||
| 601 | * 2 : handle translation descriptor (zero) | ||
| 602 | * 3 : KProcess handle | ||
| 603 | * Outputs: | ||
| 604 | * 0 : Return header | ||
| 605 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 606 | */ | ||
| 607 | static void UnlinkCRO(Interface* self) { | ||
| 608 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 1, 2); | ||
| 609 | VAddr cro_address = rp.Pop<u32>(); | ||
| 610 | Kernel::Handle process = rp.PopHandle(); | ||
| 611 | |||
| 612 | LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process); | ||
| 613 | |||
| 614 | CROHelper cro(cro_address); | ||
| 615 | |||
| 616 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 617 | |||
| 618 | if (loaded_crs == 0) { | ||
| 619 | LOG_ERROR(Service_LDR, "Not initialized"); | ||
| 620 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 621 | return; | ||
| 622 | } | ||
| 623 | |||
| 624 | if (cro_address & Memory::PAGE_MASK) { | ||
| 625 | LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||
| 626 | rb.Push(ERROR_MISALIGNED_ADDRESS); | ||
| 627 | return; | ||
| 628 | } | ||
| 629 | |||
| 630 | if (!cro.IsLoaded()) { | ||
| 631 | LOG_ERROR(Service_LDR, "Invalid or not loaded CRO"); | ||
| 632 | rb.Push(ERROR_NOT_LOADED); | ||
| 633 | return; | ||
| 634 | } | ||
| 635 | |||
| 636 | LOG_INFO(Service_LDR, "Unlinking CRO \"%s\"", cro.ModuleName().data()); | ||
| 637 | |||
| 638 | ResultCode result = cro.Unlink(loaded_crs); | ||
| 639 | if (result.IsError()) { | ||
| 640 | LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw); | ||
| 641 | } | ||
| 642 | |||
| 643 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 644 | Core::CPU().ClearInstructionCache(); | ||
| 645 | |||
| 646 | rb.Push(result); | ||
| 647 | } | ||
| 648 | |||
| 649 | /** | ||
| 650 | * LDR_RO::Shutdown service function | ||
| 651 | * Inputs: | ||
| 652 | * 0 : 0x00080042 | ||
| 653 | * 1 : original CRS buffer pointer | ||
| 654 | * 2 : handle translation descriptor (zero) | ||
| 655 | * 3 : KProcess handle | ||
| 656 | * Outputs: | ||
| 657 | * 0 : Return header | ||
| 658 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 659 | */ | ||
| 660 | static void Shutdown(Interface* self) { | ||
| 661 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 2); | ||
| 662 | VAddr crs_buffer_ptr = rp.Pop<u32>(); | ||
| 663 | Kernel::Handle process = rp.PopHandle(); | ||
| 664 | |||
| 665 | LOG_DEBUG(Service_LDR, "called, crs_buffer_ptr=0x%08X, process=0x%08X", crs_buffer_ptr, | ||
| 666 | process); | ||
| 667 | |||
| 668 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 669 | |||
| 670 | if (loaded_crs == 0) { | ||
| 671 | LOG_ERROR(Service_LDR, "Not initialized"); | ||
| 672 | rb.Push(ERROR_NOT_INITIALIZED); | ||
| 673 | return; | ||
| 674 | } | ||
| 675 | |||
| 676 | CROHelper crs(loaded_crs); | ||
| 677 | crs.Unrebase(true); | ||
| 678 | |||
| 679 | memory_synchronizer.SynchronizeOriginalMemory(); | ||
| 680 | |||
| 681 | ResultCode result = RESULT_SUCCESS; | ||
| 682 | |||
| 683 | // TODO(wwylele): verify the behaviour when buffer_ptr == address | ||
| 684 | if (loaded_crs != crs_buffer_ptr) { | ||
| 685 | result = Kernel::g_current_process->vm_manager.UnmapRange(loaded_crs, crs.GetFileSize()); | ||
| 686 | if (result.IsError()) { | ||
| 687 | LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw); | ||
| 688 | } | ||
| 689 | memory_synchronizer.RemoveMemoryBlock(loaded_crs, crs_buffer_ptr); | ||
| 690 | } | ||
| 691 | |||
| 692 | loaded_crs = 0; | ||
| 693 | rb.Push(result); | ||
| 694 | } | ||
| 695 | |||
| 696 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 697 | // clang-format off | ||
| 698 | {0x000100C2, Initialize, "Initialize"}, | ||
| 699 | {0x00020082, LoadCRR, "LoadCRR"}, | ||
| 700 | {0x00030042, UnloadCRR, "UnloadCRR"}, | ||
| 701 | {0x000402C2, LoadCRO<false>, "LoadCRO"}, | ||
| 702 | {0x000500C2, UnloadCRO, "UnloadCRO"}, | ||
| 703 | {0x00060042, LinkCRO, "LinkCRO"}, | ||
| 704 | {0x00070042, UnlinkCRO, "UnlinkCRO"}, | ||
| 705 | {0x00080042, Shutdown, "Shutdown"}, | ||
| 706 | {0x000902C2, LoadCRO<true>, "LoadCRO_New"}, | ||
| 707 | // clang-format on | ||
| 708 | }; | ||
| 709 | |||
| 710 | LDR_RO::LDR_RO() { | ||
| 711 | Register(FunctionTable); | ||
| 712 | |||
| 713 | loaded_crs = 0; | ||
| 714 | memory_synchronizer.Clear(); | ||
| 715 | } | ||
| 716 | |||
| 717 | } // namespace LDR | ||
| 718 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h deleted file mode 100644 index 0f6fe7b60..000000000 --- a/src/core/hle/service/ldr_ro/ldr_ro.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace LDR { | ||
| 11 | |||
| 12 | class LDR_RO final : public Interface { | ||
| 13 | public: | ||
| 14 | LDR_RO(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ldr:ro"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace LDR | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp deleted file mode 100644 index 0d44bf6bd..000000000 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "core/hle/service/ldr_ro/memory_synchronizer.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace LDR { | ||
| 11 | |||
| 12 | auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) { | ||
| 13 | auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(), | ||
| 14 | [=](MemoryBlock& b) { return b.original == original; }); | ||
| 15 | ASSERT(block->mapping == mapping); | ||
| 16 | return block; | ||
| 17 | } | ||
| 18 | |||
| 19 | void MemorySynchronizer::Clear() { | ||
| 20 | memory_blocks.clear(); | ||
| 21 | } | ||
| 22 | |||
| 23 | void MemorySynchronizer::AddMemoryBlock(VAddr mapping, VAddr original, u32 size) { | ||
| 24 | memory_blocks.push_back(MemoryBlock{mapping, original, size}); | ||
| 25 | } | ||
| 26 | |||
| 27 | void MemorySynchronizer::ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size) { | ||
| 28 | FindMemoryBlock(mapping, original)->size = size; | ||
| 29 | } | ||
| 30 | |||
| 31 | void MemorySynchronizer::RemoveMemoryBlock(VAddr mapping, VAddr original) { | ||
| 32 | memory_blocks.erase(FindMemoryBlock(mapping, original)); | ||
| 33 | } | ||
| 34 | |||
| 35 | void MemorySynchronizer::SynchronizeOriginalMemory() { | ||
| 36 | for (auto& block : memory_blocks) { | ||
| 37 | Memory::CopyBlock(block.original, block.mapping, block.size); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | } // namespace LDR | ||
| 42 | } // namespace Service | ||
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h deleted file mode 100644 index 438293a58..000000000 --- a/src/core/hle/service/ldr_ro/memory_synchronizer.h +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "core/memory.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace LDR { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * This is a work-around before we implement memory aliasing. | ||
| 15 | * CRS and CRO are mapped (aliased) to another memory when loading. Games can read | ||
| 16 | * from both the original buffer and the mapping memory. So we use this to synchronize | ||
| 17 | * all original buffers with mapping memory after modifying the content. | ||
| 18 | */ | ||
| 19 | class MemorySynchronizer { | ||
| 20 | public: | ||
| 21 | void Clear(); | ||
| 22 | |||
| 23 | void AddMemoryBlock(VAddr mapping, VAddr original, u32 size); | ||
| 24 | void ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size); | ||
| 25 | void RemoveMemoryBlock(VAddr mapping, VAddr original); | ||
| 26 | |||
| 27 | void SynchronizeOriginalMemory(); | ||
| 28 | |||
| 29 | private: | ||
| 30 | struct MemoryBlock { | ||
| 31 | VAddr mapping; | ||
| 32 | VAddr original; | ||
| 33 | u32 size; | ||
| 34 | }; | ||
| 35 | |||
| 36 | std::vector<MemoryBlock> memory_blocks; | ||
| 37 | |||
| 38 | auto FindMemoryBlock(VAddr mapping, VAddr original); | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // namespace LDR | ||
| 42 | } // namespace Service | ||
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp deleted file mode 100644 index 23e1ff094..000000000 --- a/src/core/hle/service/mic_u.cpp +++ /dev/null | |||
| @@ -1,346 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc.h" | ||
| 7 | #include "core/hle/kernel/event.h" | ||
| 8 | #include "core/hle/kernel/handle_table.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | ||
| 10 | #include "core/hle/kernel/shared_memory.h" | ||
| 11 | #include "core/hle/service/mic_u.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace MIC { | ||
| 15 | |||
| 16 | enum class Encoding : u8 { | ||
| 17 | PCM8 = 0, | ||
| 18 | PCM16 = 1, | ||
| 19 | PCM8Signed = 2, | ||
| 20 | PCM16Signed = 3, | ||
| 21 | }; | ||
| 22 | |||
| 23 | enum class SampleRate : u8 { | ||
| 24 | SampleRate32730 = 0, | ||
| 25 | SampleRate16360 = 1, | ||
| 26 | SampleRate10910 = 2, | ||
| 27 | SampleRate8180 = 3 | ||
| 28 | }; | ||
| 29 | |||
| 30 | static Kernel::SharedPtr<Kernel::Event> buffer_full_event; | ||
| 31 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; | ||
| 32 | static u8 mic_gain = 0; | ||
| 33 | static bool mic_power = false; | ||
| 34 | static bool is_sampling = false; | ||
| 35 | static bool allow_shell_closed; | ||
| 36 | static bool clamp = false; | ||
| 37 | static Encoding encoding; | ||
| 38 | static SampleRate sample_rate; | ||
| 39 | static s32 audio_buffer_offset; | ||
| 40 | static u32 audio_buffer_size; | ||
| 41 | static bool audio_buffer_loop; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * MIC::MapSharedMem service function | ||
| 45 | * Inputs: | ||
| 46 | * 0 : Header Code[0x00010042] | ||
| 47 | * 1 : Shared-mem size | ||
| 48 | * 2 : CopyHandleDesc | ||
| 49 | * 3 : Shared-mem handle | ||
| 50 | * Outputs: | ||
| 51 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 52 | */ | ||
| 53 | static void MapSharedMem(Interface* self) { | ||
| 54 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 55 | u32 size = cmd_buff[1]; | ||
| 56 | Kernel::Handle mem_handle = cmd_buff[3]; | ||
| 57 | shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(mem_handle); | ||
| 58 | if (shared_memory) { | ||
| 59 | shared_memory->name = "MIC_U:shared_memory"; | ||
| 60 | } | ||
| 61 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 62 | LOG_WARNING(Service_MIC, "called, size=0x%X, mem_handle=0x%08X", size, mem_handle); | ||
| 63 | } | ||
| 64 | |||
| 65 | /** | ||
| 66 | * MIC::UnmapSharedMem service function | ||
| 67 | * Inputs: | ||
| 68 | * 0 : Header Code[0x00020000] | ||
| 69 | * Outputs: | ||
| 70 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 71 | */ | ||
| 72 | static void UnmapSharedMem(Interface* self) { | ||
| 73 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 74 | |||
| 75 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 76 | LOG_WARNING(Service_MIC, "called"); | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * MIC::StartSampling service function | ||
| 81 | * Inputs: | ||
| 82 | * 0 : Header Code[0x00030140] | ||
| 83 | * 1 : Encoding | ||
| 84 | * 2 : SampleRate | ||
| 85 | * 3 : Base offset for audio data in sharedmem | ||
| 86 | * 4 : Size of the audio data in sharedmem | ||
| 87 | * 5 : Loop at end of buffer | ||
| 88 | * Outputs: | ||
| 89 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 90 | */ | ||
| 91 | static void StartSampling(Interface* self) { | ||
| 92 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 93 | |||
| 94 | encoding = static_cast<Encoding>(cmd_buff[1] & 0xFF); | ||
| 95 | sample_rate = static_cast<SampleRate>(cmd_buff[2] & 0xFF); | ||
| 96 | audio_buffer_offset = cmd_buff[3]; | ||
| 97 | audio_buffer_size = cmd_buff[4]; | ||
| 98 | audio_buffer_loop = (cmd_buff[5] & 0xFF) != 0; | ||
| 99 | |||
| 100 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 101 | is_sampling = true; | ||
| 102 | LOG_WARNING(Service_MIC, "(STUBBED) called, encoding=%u, sample_rate=%u, " | ||
| 103 | "audio_buffer_offset=%d, audio_buffer_size=%u, audio_buffer_loop=%u", | ||
| 104 | static_cast<u32>(encoding), static_cast<u32>(sample_rate), audio_buffer_offset, | ||
| 105 | audio_buffer_size, audio_buffer_loop); | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * MIC::AdjustSampling service function | ||
| 110 | * Inputs: | ||
| 111 | * 0 : Header Code[0x00040040] | ||
| 112 | * 1 : SampleRate | ||
| 113 | * Outputs: | ||
| 114 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 115 | */ | ||
| 116 | static void AdjustSampling(Interface* self) { | ||
| 117 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 118 | sample_rate = static_cast<SampleRate>(cmd_buff[1] & 0xFF); | ||
| 119 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 120 | LOG_WARNING(Service_MIC, "(STUBBED) called, sample_rate=%u", static_cast<u32>(sample_rate)); | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * MIC::StopSampling service function | ||
| 125 | * Inputs: | ||
| 126 | * 0 : Header Code[0x00050000] | ||
| 127 | * Outputs: | ||
| 128 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 129 | */ | ||
| 130 | static void StopSampling(Interface* self) { | ||
| 131 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 132 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 133 | is_sampling = false; | ||
| 134 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * MIC::IsSampling service function | ||
| 139 | * Inputs: | ||
| 140 | * 0 : Header Code[0x00060000] | ||
| 141 | * Outputs: | ||
| 142 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 143 | * 2 : 0 = sampling, non-zero = sampling | ||
| 144 | */ | ||
| 145 | static void IsSampling(Interface* self) { | ||
| 146 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 147 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 148 | cmd_buff[2] = is_sampling; | ||
| 149 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * MIC::GetBufferFullEvent service function | ||
| 154 | * Inputs: | ||
| 155 | * 0 : Header Code[0x00070000] | ||
| 156 | * Outputs: | ||
| 157 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 158 | * 3 : Event handle | ||
| 159 | */ | ||
| 160 | static void GetBufferFullEvent(Interface* self) { | ||
| 161 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 162 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 163 | cmd_buff[3] = Kernel::g_handle_table.Create(buffer_full_event).Unwrap(); | ||
| 164 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * MIC::SetGain service function | ||
| 169 | * Inputs: | ||
| 170 | * 0 : Header Code[0x00080040] | ||
| 171 | * 1 : Gain | ||
| 172 | * Outputs: | ||
| 173 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 174 | */ | ||
| 175 | static void SetGain(Interface* self) { | ||
| 176 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 177 | mic_gain = cmd_buff[1] & 0xFF; | ||
| 178 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 179 | LOG_WARNING(Service_MIC, "(STUBBED) called, mic_gain=%u", mic_gain); | ||
| 180 | } | ||
| 181 | |||
| 182 | /** | ||
| 183 | * MIC::GetGain service function | ||
| 184 | * Inputs: | ||
| 185 | * 0 : Header Code[0x00090000] | ||
| 186 | * Outputs: | ||
| 187 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 188 | * 2 : Gain | ||
| 189 | */ | ||
| 190 | static void GetGain(Interface* self) { | ||
| 191 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 192 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 193 | cmd_buff[2] = mic_gain; | ||
| 194 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * MIC::SetPower service function | ||
| 199 | * Inputs: | ||
| 200 | * 0 : Header Code[0x000A0040] | ||
| 201 | * 1 : Power (0 = off, 1 = on) | ||
| 202 | * Outputs: | ||
| 203 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 204 | */ | ||
| 205 | static void SetPower(Interface* self) { | ||
| 206 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 207 | mic_power = (cmd_buff[1] & 0xFF) != 0; | ||
| 208 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 209 | LOG_WARNING(Service_MIC, "(STUBBED) called, mic_power=%u", mic_power); | ||
| 210 | } | ||
| 211 | |||
| 212 | /** | ||
| 213 | * MIC::GetPower service function | ||
| 214 | * Inputs: | ||
| 215 | * 0 : Header Code[0x000B0000] | ||
| 216 | * Outputs: | ||
| 217 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 218 | * 2 : Power | ||
| 219 | */ | ||
| 220 | static void GetPower(Interface* self) { | ||
| 221 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 222 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 223 | cmd_buff[2] = mic_power; | ||
| 224 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * MIC::SetIirFilterMic service function | ||
| 229 | * Inputs: | ||
| 230 | * 0 : Header Code[0x000C0042] | ||
| 231 | * 1 : Size | ||
| 232 | * 2 : (Size << 4) | 0xA | ||
| 233 | * 3 : Pointer to IIR Filter Data | ||
| 234 | * Outputs: | ||
| 235 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 236 | */ | ||
| 237 | static void SetIirFilterMic(Interface* self) { | ||
| 238 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 239 | |||
| 240 | u32 size = cmd_buff[1]; | ||
| 241 | VAddr buffer = cmd_buff[3]; | ||
| 242 | |||
| 243 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 244 | LOG_WARNING(Service_MIC, "(STUBBED) called, size=0x%X, buffer=0x%08X", size, buffer); | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * MIC::SetClamp service function | ||
| 249 | * Inputs: | ||
| 250 | * 0 : Header Code[0x000D0040] | ||
| 251 | * 1 : Clamp (0 = don't clamp, non-zero = clamp) | ||
| 252 | * Outputs: | ||
| 253 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 254 | */ | ||
| 255 | static void SetClamp(Interface* self) { | ||
| 256 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 257 | clamp = (cmd_buff[1] & 0xFF) != 0; | ||
| 258 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 259 | LOG_WARNING(Service_MIC, "(STUBBED) called, clamp=%u", clamp); | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | ||
| 263 | * MIC::GetClamp service function | ||
| 264 | * Inputs: | ||
| 265 | * 0 : Header Code[0x000E0000] | ||
| 266 | * Outputs: | ||
| 267 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 268 | * 2 : Clamp (0 = don't clamp, non-zero = clamp) | ||
| 269 | */ | ||
| 270 | static void GetClamp(Interface* self) { | ||
| 271 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 272 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 273 | cmd_buff[2] = clamp; | ||
| 274 | LOG_WARNING(Service_MIC, "(STUBBED) called"); | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * MIC::SetAllowShellClosed service function | ||
| 279 | * Inputs: | ||
| 280 | * 0 : Header Code[0x000D0040] | ||
| 281 | * 1 : Sampling allowed while shell closed (0 = disallow, non-zero = allow) | ||
| 282 | * Outputs: | ||
| 283 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 284 | */ | ||
| 285 | static void SetAllowShellClosed(Interface* self) { | ||
| 286 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 287 | allow_shell_closed = (cmd_buff[1] & 0xFF) != 0; | ||
| 288 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 289 | LOG_WARNING(Service_MIC, "(STUBBED) called, allow_shell_closed=%u", allow_shell_closed); | ||
| 290 | } | ||
| 291 | |||
| 292 | /** | ||
| 293 | * MIC_U::SetClientVersion service function | ||
| 294 | * Inputs: | ||
| 295 | * 1 : Used SDK Version | ||
| 296 | * Outputs: | ||
| 297 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 298 | */ | ||
| 299 | static void SetClientVersion(Interface* self) { | ||
| 300 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 301 | |||
| 302 | const u32 version = cmd_buff[1]; | ||
| 303 | self->SetVersion(version); | ||
| 304 | |||
| 305 | LOG_WARNING(Service_MIC, "(STUBBED) called, version: 0x%08X", version); | ||
| 306 | |||
| 307 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 308 | } | ||
| 309 | |||
| 310 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 311 | {0x00010042, MapSharedMem, "MapSharedMem"}, | ||
| 312 | {0x00020000, UnmapSharedMem, "UnmapSharedMem"}, | ||
| 313 | {0x00030140, StartSampling, "StartSampling"}, | ||
| 314 | {0x00040040, AdjustSampling, "AdjustSampling"}, | ||
| 315 | {0x00050000, StopSampling, "StopSampling"}, | ||
| 316 | {0x00060000, IsSampling, "IsSampling"}, | ||
| 317 | {0x00070000, GetBufferFullEvent, "GetBufferFullEvent"}, | ||
| 318 | {0x00080040, SetGain, "SetGain"}, | ||
| 319 | {0x00090000, GetGain, "GetGain"}, | ||
| 320 | {0x000A0040, SetPower, "SetPower"}, | ||
| 321 | {0x000B0000, GetPower, "GetPower"}, | ||
| 322 | {0x000C0042, SetIirFilterMic, "SetIirFilterMic"}, | ||
| 323 | {0x000D0040, SetClamp, "SetClamp"}, | ||
| 324 | {0x000E0000, GetClamp, "GetClamp"}, | ||
| 325 | {0x000F0040, SetAllowShellClosed, "SetAllowShellClosed"}, | ||
| 326 | {0x00100040, SetClientVersion, "SetClientVersion"}, | ||
| 327 | }; | ||
| 328 | |||
| 329 | MIC_U::MIC_U() { | ||
| 330 | Register(FunctionTable); | ||
| 331 | shared_memory = nullptr; | ||
| 332 | buffer_full_event = | ||
| 333 | Kernel::Event::Create(Kernel::ResetType::OneShot, "MIC_U::buffer_full_event"); | ||
| 334 | mic_gain = 0; | ||
| 335 | mic_power = false; | ||
| 336 | is_sampling = false; | ||
| 337 | clamp = false; | ||
| 338 | } | ||
| 339 | |||
| 340 | MIC_U::~MIC_U() { | ||
| 341 | shared_memory = nullptr; | ||
| 342 | buffer_full_event = nullptr; | ||
| 343 | } | ||
| 344 | |||
| 345 | } // namespace MIC | ||
| 346 | } // namespace Service | ||
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h deleted file mode 100644 index ec2b67ab8..000000000 --- a/src/core/hle/service/mic_u.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace MIC { | ||
| 11 | |||
| 12 | class MIC_U final : public Interface { | ||
| 13 | public: | ||
| 14 | MIC_U(); | ||
| 15 | ~MIC_U(); | ||
| 16 | |||
| 17 | std::string GetPortName() const override { | ||
| 18 | return "mic:u"; | ||
| 19 | } | ||
| 20 | }; | ||
| 21 | |||
| 22 | } // namespace MIC | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/mvd/mvd.cpp b/src/core/hle/service/mvd/mvd.cpp deleted file mode 100644 index 9416fe5d6..000000000 --- a/src/core/hle/service/mvd/mvd.cpp +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/mvd/mvd.h" | ||
| 6 | #include "core/hle/service/mvd/mvd_std.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace MVD { | ||
| 11 | |||
| 12 | void Init() { | ||
| 13 | AddService(new MVD_STD()); | ||
| 14 | } | ||
| 15 | |||
| 16 | } // namespace MVD | ||
| 17 | } // namespace Service | ||
diff --git a/src/core/hle/service/mvd/mvd.h b/src/core/hle/service/mvd/mvd.h deleted file mode 100644 index 7b212e839..000000000 --- a/src/core/hle/service/mvd/mvd.h +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace MVD { | ||
| 9 | |||
| 10 | /// Initializes all MVD services. | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | } // namespace MVD | ||
| 14 | } // namespace Service | ||
diff --git a/src/core/hle/service/mvd/mvd_std.cpp b/src/core/hle/service/mvd/mvd_std.cpp deleted file mode 100644 index fd7ca87d3..000000000 --- a/src/core/hle/service/mvd/mvd_std.cpp +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/mvd/mvd_std.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace MVD { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | {0x00010082, nullptr, "Initialize"}, | ||
| 13 | {0x00020000, nullptr, "Shutdown"}, | ||
| 14 | {0x00030300, nullptr, "CalculateWorkBufSize"}, | ||
| 15 | {0x000400C0, nullptr, "CalculateImageSize"}, | ||
| 16 | {0x00080142, nullptr, "ProcessNALUnit"}, | ||
| 17 | {0x00090042, nullptr, "ControlFrameRendering"}, | ||
| 18 | {0x000A0000, nullptr, "GetStatus"}, | ||
| 19 | {0x000B0000, nullptr, "GetStatusOther"}, | ||
| 20 | {0x001D0042, nullptr, "GetConfig"}, | ||
| 21 | {0x001E0044, nullptr, "SetConfig"}, | ||
| 22 | {0x001F0902, nullptr, "SetOutputBuffer"}, | ||
| 23 | {0x00210100, nullptr, "OverrideOutputBuffers"} | ||
| 24 | // clang-format on | ||
| 25 | }; | ||
| 26 | |||
| 27 | MVD_STD::MVD_STD() { | ||
| 28 | Register(FunctionTable); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace MVD | ||
| 32 | } // namespace Service | ||
diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h deleted file mode 100644 index 7db9e2e50..000000000 --- a/src/core/hle/service/mvd/mvd_std.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace MVD { | ||
| 11 | |||
| 12 | class MVD_STD final : public Interface { | ||
| 13 | public: | ||
| 14 | MVD_STD(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "mvd:std"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace MVD | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp deleted file mode 100644 index 096c0cdac..000000000 --- a/src/core/hle/service/ndm/ndm.cpp +++ /dev/null | |||
| @@ -1,239 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/hle/ipc.h" | ||
| 9 | #include "core/hle/service/ndm/ndm.h" | ||
| 10 | #include "core/hle/service/ndm/ndm_u.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace NDM { | ||
| 15 | |||
| 16 | enum : u32 { | ||
| 17 | DEFAULT_RETRY_INTERVAL = 10, | ||
| 18 | DEFAULT_SCAN_INTERVAL = 30, | ||
| 19 | }; | ||
| 20 | |||
| 21 | static DaemonMask daemon_bit_mask = DaemonMask::Default; | ||
| 22 | static DaemonMask default_daemon_bit_mask = DaemonMask::Default; | ||
| 23 | static std::array<DaemonStatus, 4> daemon_status = { | ||
| 24 | DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle, | ||
| 25 | }; | ||
| 26 | static ExclusiveState exclusive_state = ExclusiveState::None; | ||
| 27 | static u32 scan_interval = DEFAULT_SCAN_INTERVAL; | ||
| 28 | static u32 retry_interval = DEFAULT_RETRY_INTERVAL; | ||
| 29 | static bool daemon_lock_enabled = false; | ||
| 30 | |||
| 31 | void EnterExclusiveState(Service::Interface* self) { | ||
| 32 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 33 | exclusive_state = static_cast<ExclusiveState>(cmd_buff[1]); | ||
| 34 | |||
| 35 | cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||
| 36 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 37 | LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state); | ||
| 38 | } | ||
| 39 | |||
| 40 | void LeaveExclusiveState(Service::Interface* self) { | ||
| 41 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 42 | exclusive_state = ExclusiveState::None; | ||
| 43 | |||
| 44 | cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0); | ||
| 45 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 46 | LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state); | ||
| 47 | } | ||
| 48 | |||
| 49 | void QueryExclusiveMode(Service::Interface* self) { | ||
| 50 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 51 | |||
| 52 | cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0); | ||
| 53 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 54 | cmd_buff[2] = static_cast<u32>(exclusive_state); | ||
| 55 | LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state); | ||
| 56 | } | ||
| 57 | |||
| 58 | void LockState(Service::Interface* self) { | ||
| 59 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 60 | daemon_lock_enabled = true; | ||
| 61 | |||
| 62 | cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0); | ||
| 63 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 64 | LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled); | ||
| 65 | } | ||
| 66 | |||
| 67 | void UnlockState(Service::Interface* self) { | ||
| 68 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 69 | daemon_lock_enabled = false; | ||
| 70 | |||
| 71 | cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0); | ||
| 72 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 73 | LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled); | ||
| 74 | } | ||
| 75 | |||
| 76 | void SuspendDaemons(Service::Interface* self) { | ||
| 77 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 78 | u32 bit_mask = cmd_buff[1] & 0xF; | ||
| 79 | daemon_bit_mask = | ||
| 80 | static_cast<DaemonMask>(static_cast<u32>(default_daemon_bit_mask) & ~bit_mask); | ||
| 81 | for (size_t index = 0; index < daemon_status.size(); ++index) { | ||
| 82 | if (bit_mask & (1 << index)) { | ||
| 83 | daemon_status[index] = DaemonStatus::Suspended; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | cmd_buff[0] = IPC::MakeHeader(0x6, 1, 0); | ||
| 88 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 89 | LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask); | ||
| 90 | } | ||
| 91 | |||
| 92 | void ResumeDaemons(Service::Interface* self) { | ||
| 93 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 94 | u32 bit_mask = cmd_buff[1] & 0xF; | ||
| 95 | daemon_bit_mask = static_cast<DaemonMask>(static_cast<u32>(daemon_bit_mask) | bit_mask); | ||
| 96 | for (size_t index = 0; index < daemon_status.size(); ++index) { | ||
| 97 | if (bit_mask & (1 << index)) { | ||
| 98 | daemon_status[index] = DaemonStatus::Idle; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0); | ||
| 103 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 104 | LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask); | ||
| 105 | } | ||
| 106 | |||
| 107 | void SuspendScheduler(Service::Interface* self) { | ||
| 108 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 109 | |||
| 110 | cmd_buff[0] = IPC::MakeHeader(0x8, 1, 0); | ||
| 111 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 112 | LOG_WARNING(Service_NDM, "(STUBBED) called"); | ||
| 113 | } | ||
| 114 | |||
| 115 | void ResumeScheduler(Service::Interface* self) { | ||
| 116 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 117 | |||
| 118 | cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0); | ||
| 119 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 120 | LOG_WARNING(Service_NDM, "(STUBBED) called"); | ||
| 121 | } | ||
| 122 | |||
| 123 | void QueryStatus(Service::Interface* self) { | ||
| 124 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 125 | u32 daemon = cmd_buff[1] & 0xF; | ||
| 126 | |||
| 127 | cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0); | ||
| 128 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 129 | cmd_buff[2] = static_cast<u32>(daemon_status.at(daemon)); | ||
| 130 | LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X, daemon_status=0x%08X", daemon, cmd_buff[2]); | ||
| 131 | } | ||
| 132 | |||
| 133 | void GetDaemonDisableCount(Service::Interface* self) { | ||
| 134 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 135 | u32 daemon = cmd_buff[1] & 0xF; | ||
| 136 | |||
| 137 | cmd_buff[0] = IPC::MakeHeader(0xE, 3, 0); | ||
| 138 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 139 | cmd_buff[2] = 0; | ||
| 140 | cmd_buff[3] = 0; | ||
| 141 | LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X", daemon); | ||
| 142 | } | ||
| 143 | |||
| 144 | void GetSchedulerDisableCount(Service::Interface* self) { | ||
| 145 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 146 | |||
| 147 | cmd_buff[0] = IPC::MakeHeader(0xF, 3, 0); | ||
| 148 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 149 | cmd_buff[2] = 0; | ||
| 150 | cmd_buff[3] = 0; | ||
| 151 | LOG_WARNING(Service_NDM, "(STUBBED) called"); | ||
| 152 | } | ||
| 153 | |||
| 154 | void SetScanInterval(Service::Interface* self) { | ||
| 155 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 156 | scan_interval = cmd_buff[1]; | ||
| 157 | |||
| 158 | cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0); | ||
| 159 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 160 | LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval); | ||
| 161 | } | ||
| 162 | |||
| 163 | void GetScanInterval(Service::Interface* self) { | ||
| 164 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 165 | |||
| 166 | cmd_buff[0] = IPC::MakeHeader(0x11, 2, 0); | ||
| 167 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 168 | cmd_buff[2] = scan_interval; | ||
| 169 | LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval); | ||
| 170 | } | ||
| 171 | |||
| 172 | void SetRetryInterval(Service::Interface* self) { | ||
| 173 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 174 | retry_interval = cmd_buff[1]; | ||
| 175 | |||
| 176 | cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0); | ||
| 177 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 178 | LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval); | ||
| 179 | } | ||
| 180 | |||
| 181 | void GetRetryInterval(Service::Interface* self) { | ||
| 182 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 183 | |||
| 184 | cmd_buff[0] = IPC::MakeHeader(0x13, 2, 0); | ||
| 185 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 186 | cmd_buff[2] = retry_interval; | ||
| 187 | LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval); | ||
| 188 | } | ||
| 189 | |||
| 190 | void OverrideDefaultDaemons(Service::Interface* self) { | ||
| 191 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 192 | u32 bit_mask = cmd_buff[1] & 0xF; | ||
| 193 | default_daemon_bit_mask = static_cast<DaemonMask>(bit_mask); | ||
| 194 | daemon_bit_mask = default_daemon_bit_mask; | ||
| 195 | for (size_t index = 0; index < daemon_status.size(); ++index) { | ||
| 196 | if (bit_mask & (1 << index)) { | ||
| 197 | daemon_status[index] = DaemonStatus::Idle; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0); | ||
| 202 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 203 | LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask); | ||
| 204 | } | ||
| 205 | |||
| 206 | void ResetDefaultDaemons(Service::Interface* self) { | ||
| 207 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 208 | default_daemon_bit_mask = DaemonMask::Default; | ||
| 209 | |||
| 210 | cmd_buff[0] = IPC::MakeHeader(0x15, 1, 0); | ||
| 211 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 212 | LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask); | ||
| 213 | } | ||
| 214 | |||
| 215 | void GetDefaultDaemons(Service::Interface* self) { | ||
| 216 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 217 | |||
| 218 | cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0); | ||
| 219 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 220 | cmd_buff[2] = static_cast<u32>(default_daemon_bit_mask); | ||
| 221 | LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask); | ||
| 222 | } | ||
| 223 | |||
| 224 | void ClearHalfAwakeMacFilter(Service::Interface* self) { | ||
| 225 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 226 | |||
| 227 | cmd_buff[0] = IPC::MakeHeader(0x17, 1, 0); | ||
| 228 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 229 | LOG_WARNING(Service_NDM, "(STUBBED) called"); | ||
| 230 | } | ||
| 231 | |||
| 232 | void Init() { | ||
| 233 | AddService(new NDM_U_Interface); | ||
| 234 | } | ||
| 235 | |||
| 236 | void Shutdown() {} | ||
| 237 | |||
| 238 | } // namespace NDM | ||
| 239 | } // namespace Service | ||
diff --git a/src/core/hle/service/ndm/ndm.h b/src/core/hle/service/ndm/ndm.h deleted file mode 100644 index 979e7fcf1..000000000 --- a/src/core/hle/service/ndm/ndm.h +++ /dev/null | |||
| @@ -1,251 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | |||
| 11 | class Interface; | ||
| 12 | |||
| 13 | namespace NDM { | ||
| 14 | |||
| 15 | enum class Daemon : u32 { | ||
| 16 | Cec = 0, | ||
| 17 | Boss = 1, | ||
| 18 | Nim = 2, | ||
| 19 | Friend = 3, | ||
| 20 | }; | ||
| 21 | |||
| 22 | enum class DaemonMask : u32 { | ||
| 23 | None = 0, | ||
| 24 | Cec = (1 << static_cast<u32>(Daemon::Cec)), | ||
| 25 | Boss = (1 << static_cast<u32>(Daemon::Boss)), | ||
| 26 | Nim = (1 << static_cast<u32>(Daemon::Nim)), | ||
| 27 | Friend = (1 << static_cast<u32>(Daemon::Friend)), | ||
| 28 | Default = Cec | Friend, | ||
| 29 | All = Cec | Boss | Nim | Friend, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum class DaemonStatus : u32 { Busy = 0, Idle = 1, Suspending = 2, Suspended = 3 }; | ||
| 33 | |||
| 34 | enum class ExclusiveState : u32 { | ||
| 35 | None = 0, | ||
| 36 | Infrastructure = 1, | ||
| 37 | LocalCommunications = 2, | ||
| 38 | Streetpass = 3, | ||
| 39 | StreetpassData = 4, | ||
| 40 | }; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * NDM::EnterExclusiveState service function | ||
| 44 | * Inputs: | ||
| 45 | * 0 : Header code [0x00010042] | ||
| 46 | * 1 : Exclusive State | ||
| 47 | * 2 : 0x20 | ||
| 48 | * Outputs: | ||
| 49 | * 1 : Result, 0 on success, otherwise error code | ||
| 50 | */ | ||
| 51 | void EnterExclusiveState(Service::Interface* self); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * NDM::LeaveExclusiveState service function | ||
| 55 | * Inputs: | ||
| 56 | * 0 : Header code [0x00020002] | ||
| 57 | * 1 : 0x20 | ||
| 58 | * Outputs: | ||
| 59 | * 1 : Result, 0 on success, otherwise error code | ||
| 60 | */ | ||
| 61 | void LeaveExclusiveState(Service::Interface* self); | ||
| 62 | |||
| 63 | /** | ||
| 64 | * NDM::QueryExclusiveMode service function | ||
| 65 | * Inputs: | ||
| 66 | * 0 : Header code [0x00030000] | ||
| 67 | * Outputs: | ||
| 68 | * 1 : Result, 0 on success, otherwise error code | ||
| 69 | * 2 : Current Exclusive State | ||
| 70 | */ | ||
| 71 | void QueryExclusiveMode(Service::Interface* self); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * NDM::LockState service function | ||
| 75 | * Inputs: | ||
| 76 | * 0 : Header code [0x00040002] | ||
| 77 | * Outputs: | ||
| 78 | * 1 : Result, 0 on success, otherwise error code | ||
| 79 | */ | ||
| 80 | void LockState(Service::Interface* self); | ||
| 81 | |||
| 82 | /** | ||
| 83 | * NDM::UnlockState service function | ||
| 84 | * Inputs: | ||
| 85 | * 0 : Header code [0x00050002] | ||
| 86 | * Outputs: | ||
| 87 | * 1 : Result, 0 on success, otherwise error code | ||
| 88 | */ | ||
| 89 | void UnlockState(Service::Interface* self); | ||
| 90 | |||
| 91 | /** | ||
| 92 | * NDM::SuspendDaemons service function | ||
| 93 | * Inputs: | ||
| 94 | * 0 : Header code [0x00060040] | ||
| 95 | * 1 : Daemon bit mask | ||
| 96 | * Outputs: | ||
| 97 | * 1 : Result, 0 on success, otherwise error code | ||
| 98 | */ | ||
| 99 | void SuspendDaemons(Service::Interface* self); | ||
| 100 | |||
| 101 | /** | ||
| 102 | * NDM::ResumeDaemons service function | ||
| 103 | * Inputs: | ||
| 104 | * 0 : Header code [0x00070040] | ||
| 105 | * 1 : Daemon bit mask | ||
| 106 | * Outputs: | ||
| 107 | * 1 : Result, 0 on success, otherwise error code | ||
| 108 | */ | ||
| 109 | void ResumeDaemons(Service::Interface* self); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * NDM::SuspendScheduler service function | ||
| 113 | * Inputs: | ||
| 114 | * 0 : Header code [0x00080040] | ||
| 115 | * Outputs: | ||
| 116 | * 1 : Result, 0 on success, otherwise error code | ||
| 117 | */ | ||
| 118 | void SuspendScheduler(Service::Interface* self); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * NDM::ResumeScheduler service function | ||
| 122 | * Inputs: | ||
| 123 | * 0 : Header code [0x00090000] | ||
| 124 | * Outputs: | ||
| 125 | * 1 : Result, 0 on success, otherwise error code | ||
| 126 | */ | ||
| 127 | void ResumeScheduler(Service::Interface* self); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * NDM::QueryStatus service function | ||
| 131 | * Inputs: | ||
| 132 | * 0 : Header code [0x000D0040] | ||
| 133 | * 1 : Daemon | ||
| 134 | * Outputs: | ||
| 135 | * 1 : Result, 0 on success, otherwise error code | ||
| 136 | * 2 : Daemon status | ||
| 137 | */ | ||
| 138 | void QueryStatus(Service::Interface* self); | ||
| 139 | |||
| 140 | /** | ||
| 141 | * NDM::GetDaemonDisableCount service function | ||
| 142 | * Inputs: | ||
| 143 | * 0 : Header code [0x000E0040] | ||
| 144 | * 1 : Daemon | ||
| 145 | * Outputs: | ||
| 146 | * 1 : Result, 0 on success, otherwise error code | ||
| 147 | * 2 : Current process disable count | ||
| 148 | * 3 : Total disable count | ||
| 149 | */ | ||
| 150 | void GetDaemonDisableCount(Service::Interface* self); | ||
| 151 | |||
| 152 | /** | ||
| 153 | * NDM::GetSchedulerDisableCount service function | ||
| 154 | * Inputs: | ||
| 155 | * 0 : Header code [0x000F0000] | ||
| 156 | * Outputs: | ||
| 157 | * 1 : Result, 0 on success, otherwise error code | ||
| 158 | * 2 : Current process disable count | ||
| 159 | * 3 : Total disable count | ||
| 160 | */ | ||
| 161 | void GetSchedulerDisableCount(Service::Interface* self); | ||
| 162 | |||
| 163 | /** | ||
| 164 | * NDM::SetScanInterval service function | ||
| 165 | * Inputs: | ||
| 166 | * 0 : Header code [0x00100040] | ||
| 167 | * 1 : Interval (default = 30) | ||
| 168 | * Outputs: | ||
| 169 | * 1 : Result, 0 on success, otherwise error code | ||
| 170 | */ | ||
| 171 | void SetScanInterval(Service::Interface* self); | ||
| 172 | |||
| 173 | /** | ||
| 174 | * NDM::GetScanInterval service function | ||
| 175 | * Inputs: | ||
| 176 | * 0 : Header code [0x00110000] | ||
| 177 | * Outputs: | ||
| 178 | * 1 : Result, 0 on success, otherwise error code | ||
| 179 | * 2 : Interval (default = 30) | ||
| 180 | */ | ||
| 181 | void GetScanInterval(Service::Interface* self); | ||
| 182 | |||
| 183 | /** | ||
| 184 | * NDM::SetRetryInterval service function | ||
| 185 | * Inputs: | ||
| 186 | * 0 : Header code [0x00120040] | ||
| 187 | * 1 : Interval (default = 10) | ||
| 188 | * Outputs: | ||
| 189 | * 1 : Result, 0 on success, otherwise error code | ||
| 190 | */ | ||
| 191 | void SetRetryInterval(Service::Interface* self); | ||
| 192 | |||
| 193 | /** | ||
| 194 | * NDM::GetRetryInterval service function | ||
| 195 | * Inputs: | ||
| 196 | * 0 : Header code [0x00130000] | ||
| 197 | * Outputs: | ||
| 198 | * 1 : Result, 0 on success, otherwise error code | ||
| 199 | * 2 : Interval (default = 10) | ||
| 200 | */ | ||
| 201 | void GetRetryInterval(Service::Interface* self); | ||
| 202 | |||
| 203 | /** | ||
| 204 | * NDM::OverrideDefaultDaemons service function | ||
| 205 | * Inputs: | ||
| 206 | * 0 : Header code [0x00140040] | ||
| 207 | * 1 : Daemon bit mask | ||
| 208 | * Outputs: | ||
| 209 | * 1 : Result, 0 on success, otherwise error code | ||
| 210 | */ | ||
| 211 | void OverrideDefaultDaemons(Service::Interface* self); | ||
| 212 | |||
| 213 | /** | ||
| 214 | * NDM::ResetDefaultDaemons service function | ||
| 215 | * Inputs: | ||
| 216 | * 0 : Header code [0x00150000] | ||
| 217 | * Outputs: | ||
| 218 | * 1 : Result, 0 on success, otherwise error code | ||
| 219 | */ | ||
| 220 | void ResetDefaultDaemons(Service::Interface* self); | ||
| 221 | |||
| 222 | /** | ||
| 223 | * NDM::GetDefaultDaemons service function | ||
| 224 | * Inputs: | ||
| 225 | * 0 : Header code [0x00160000] | ||
| 226 | * Outputs: | ||
| 227 | * 1 : Result, 0 on success, otherwise error code | ||
| 228 | * 2 : Daemon bit mask | ||
| 229 | * Note: | ||
| 230 | * Gets the current default daemon bit mask. The default value is (DAEMONMASK_CEC | | ||
| 231 | * DAEMONMASK_FRIENDS) | ||
| 232 | */ | ||
| 233 | void GetDefaultDaemons(Service::Interface* self); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * NDM::ClearHalfAwakeMacFilter service function | ||
| 237 | * Inputs: | ||
| 238 | * 0 : Header code [0x00170000] | ||
| 239 | * Outputs: | ||
| 240 | * 1 : Result, 0 on success, otherwise error code | ||
| 241 | */ | ||
| 242 | void ClearHalfAwakeMacFilter(Service::Interface* self); | ||
| 243 | |||
| 244 | /// Initialize NDM service | ||
| 245 | void Init(); | ||
| 246 | |||
| 247 | /// Shutdown NDM service | ||
| 248 | void Shutdown(); | ||
| 249 | |||
| 250 | } // namespace NDM | ||
| 251 | } // namespace Service | ||
diff --git a/src/core/hle/service/ndm/ndm_u.cpp b/src/core/hle/service/ndm/ndm_u.cpp deleted file mode 100644 index f5c7a341a..000000000 --- a/src/core/hle/service/ndm/ndm_u.cpp +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ndm/ndm.h" | ||
| 6 | #include "core/hle/service/ndm/ndm_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NDM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010042, EnterExclusiveState, "EnterExclusiveState"}, | ||
| 13 | {0x00020002, LeaveExclusiveState, "LeaveExclusiveState"}, | ||
| 14 | {0x00030000, QueryExclusiveMode, "QueryExclusiveMode"}, | ||
| 15 | {0x00040002, LockState, "LockState"}, | ||
| 16 | {0x00050002, UnlockState, "UnlockState"}, | ||
| 17 | {0x00060040, SuspendDaemons, "SuspendDaemons"}, | ||
| 18 | {0x00070040, ResumeDaemons, "ResumeDaemons"}, | ||
| 19 | {0x00080040, SuspendScheduler, "SuspendScheduler"}, | ||
| 20 | {0x00090000, ResumeScheduler, "ResumeScheduler"}, | ||
| 21 | {0x000A0000, nullptr, "GetCurrentState"}, | ||
| 22 | {0x000B0000, nullptr, "GetTargetState"}, | ||
| 23 | {0x000C0000, nullptr, "<Stubbed>"}, | ||
| 24 | {0x000D0040, QueryStatus, "QueryStatus"}, | ||
| 25 | {0x000E0040, GetDaemonDisableCount, "GetDaemonDisableCount"}, | ||
| 26 | {0x000F0000, GetSchedulerDisableCount, "GetSchedulerDisableCount"}, | ||
| 27 | {0x00100040, SetScanInterval, "SetScanInterval"}, | ||
| 28 | {0x00110000, GetScanInterval, "GetScanInterval"}, | ||
| 29 | {0x00120040, SetRetryInterval, "SetRetryInterval"}, | ||
| 30 | {0x00130000, GetRetryInterval, "GetRetryInterval"}, | ||
| 31 | {0x00140040, OverrideDefaultDaemons, "OverrideDefaultDaemons"}, | ||
| 32 | {0x00150000, ResetDefaultDaemons, "ResetDefaultDaemons"}, | ||
| 33 | {0x00160000, GetDefaultDaemons, "GetDefaultDaemons"}, | ||
| 34 | {0x00170000, ClearHalfAwakeMacFilter, "ClearHalfAwakeMacFilter"}, | ||
| 35 | }; | ||
| 36 | |||
| 37 | NDM_U_Interface::NDM_U_Interface() { | ||
| 38 | Register(FunctionTable); | ||
| 39 | } | ||
| 40 | |||
| 41 | } // namespace NDM | ||
| 42 | } // namespace Service | ||
diff --git a/src/core/hle/service/ndm/ndm_u.h b/src/core/hle/service/ndm/ndm_u.h deleted file mode 100644 index d567abc84..000000000 --- a/src/core/hle/service/ndm/ndm_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NDM { | ||
| 11 | |||
| 12 | class NDM_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NDM_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ndm:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NDM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp deleted file mode 100644 index 8b70ec45b..000000000 --- a/src/core/hle/service/news/news.cpp +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/service/news/news.h" | ||
| 7 | #include "core/hle/service/news/news_s.h" | ||
| 8 | #include "core/hle/service/news/news_u.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace NEWS { | ||
| 13 | |||
| 14 | void Init() { | ||
| 15 | using namespace Kernel; | ||
| 16 | |||
| 17 | AddService(new NEWS_S_Interface); | ||
| 18 | AddService(new NEWS_U_Interface); | ||
| 19 | } | ||
| 20 | |||
| 21 | void Shutdown() {} | ||
| 22 | |||
| 23 | } // namespace NEWS | ||
| 24 | |||
| 25 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h deleted file mode 100644 index 46a3ffcb5..000000000 --- a/src/core/hle/service/news/news.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NEWS { | ||
| 9 | |||
| 10 | /// Initialize NEWS service(s) | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | /// Shutdown NEWS service(s) | ||
| 14 | void Shutdown(); | ||
| 15 | |||
| 16 | } // namespace NEWS | ||
| 17 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp deleted file mode 100644 index dda3d0f6a..000000000 --- a/src/core/hle/service/news/news_s.cpp +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/news/news.h" | ||
| 6 | #include "core/hle/service/news/news_s.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NEWS { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x000100C6, nullptr, "AddNotification"}, | ||
| 13 | {0x00050000, nullptr, "GetTotalNotifications"}, | ||
| 14 | {0x00060042, nullptr, "SetNewsDBHeader"}, | ||
| 15 | {0x00070082, nullptr, "SetNotificationHeader"}, | ||
| 16 | {0x00080082, nullptr, "SetNotificationMessage"}, | ||
| 17 | {0x00090082, nullptr, "SetNotificationImage"}, | ||
| 18 | {0x000A0042, nullptr, "GetNewsDBHeader"}, | ||
| 19 | {0x000B0082, nullptr, "GetNotificationHeader"}, | ||
| 20 | {0x000C0082, nullptr, "GetNotificationMessage"}, | ||
| 21 | {0x000D0082, nullptr, "GetNotificationImage"}, | ||
| 22 | {0x000E0040, nullptr, "SetInfoLEDPattern"}, | ||
| 23 | {0x00120082, nullptr, "GetNotificationHeaderOther"}, | ||
| 24 | {0x00130000, nullptr, "WriteNewsDBSavedata"}, | ||
| 25 | }; | ||
| 26 | |||
| 27 | NEWS_S_Interface::NEWS_S_Interface() { | ||
| 28 | Register(FunctionTable); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace NEWS | ||
| 32 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news_s.h b/src/core/hle/service/news/news_s.h deleted file mode 100644 index f58b969a8..000000000 --- a/src/core/hle/service/news/news_s.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NEWS { | ||
| 11 | |||
| 12 | class NEWS_S_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NEWS_S_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "news:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NEWS | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp deleted file mode 100644 index a07e466de..000000000 --- a/src/core/hle/service/news/news_u.cpp +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/news/news_u.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NEWS { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x000100C6, nullptr, "AddNotification"}, | ||
| 12 | }; | ||
| 13 | |||
| 14 | NEWS_U_Interface::NEWS_U_Interface() { | ||
| 15 | Register(FunctionTable); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace NEWS | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/news/news_u.h b/src/core/hle/service/news/news_u.h deleted file mode 100644 index 2720053d0..000000000 --- a/src/core/hle/service/news/news_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NEWS { | ||
| 11 | |||
| 12 | class NEWS_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NEWS_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "news:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NEWS | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp deleted file mode 100644 index cb09ed0b7..000000000 --- a/src/core/hle/service/nfc/nfc.cpp +++ /dev/null | |||
| @@ -1,145 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/ipc.h" | ||
| 6 | #include "core/hle/kernel/event.h" | ||
| 7 | #include "core/hle/kernel/handle_table.h" | ||
| 8 | #include "core/hle/service/nfc/nfc.h" | ||
| 9 | #include "core/hle/service/nfc/nfc_m.h" | ||
| 10 | #include "core/hle/service/nfc/nfc_u.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | namespace NFC { | ||
| 14 | |||
| 15 | static Kernel::SharedPtr<Kernel::Event> tag_in_range_event; | ||
| 16 | static Kernel::SharedPtr<Kernel::Event> tag_out_of_range_event; | ||
| 17 | static TagState nfc_tag_state = TagState::NotInitialized; | ||
| 18 | static CommunicationStatus nfc_status = CommunicationStatus::NfcInitialized; | ||
| 19 | |||
| 20 | void Initialize(Interface* self) { | ||
| 21 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 22 | |||
| 23 | u8 param = static_cast<u8>(cmd_buff[1] & 0xFF); | ||
| 24 | |||
| 25 | nfc_tag_state = TagState::NotScanning; | ||
| 26 | |||
| 27 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 28 | LOG_WARNING(Service_NFC, "(STUBBED) called, param=%u", param); | ||
| 29 | } | ||
| 30 | |||
| 31 | void Shutdown(Interface* self) { | ||
| 32 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 33 | |||
| 34 | u8 param = static_cast<u8>(cmd_buff[1] & 0xFF); | ||
| 35 | nfc_tag_state = TagState::NotInitialized; | ||
| 36 | |||
| 37 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 38 | LOG_WARNING(Service_NFC, "(STUBBED) called, param=%u", param); | ||
| 39 | } | ||
| 40 | |||
| 41 | void StartCommunication(Interface* self) { | ||
| 42 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 43 | |||
| 44 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 45 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 46 | } | ||
| 47 | |||
| 48 | void StopCommunication(Interface* self) { | ||
| 49 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 50 | |||
| 51 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 52 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 53 | } | ||
| 54 | |||
| 55 | void StartTagScanning(Interface* self) { | ||
| 56 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 57 | |||
| 58 | nfc_tag_state = TagState::TagInRange; | ||
| 59 | tag_in_range_event->Signal(); | ||
| 60 | |||
| 61 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 62 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 63 | } | ||
| 64 | |||
| 65 | void StopTagScanning(Interface* self) { | ||
| 66 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 67 | |||
| 68 | nfc_tag_state = TagState::NotScanning; | ||
| 69 | |||
| 70 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 71 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 72 | } | ||
| 73 | |||
| 74 | void LoadAmiiboData(Interface* self) { | ||
| 75 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 76 | |||
| 77 | nfc_tag_state = TagState::TagDataLoaded; | ||
| 78 | |||
| 79 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 80 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 81 | } | ||
| 82 | |||
| 83 | void ResetTagScanState(Interface* self) { | ||
| 84 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 85 | |||
| 86 | nfc_tag_state = TagState::NotScanning; | ||
| 87 | |||
| 88 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 89 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 90 | } | ||
| 91 | |||
| 92 | void GetTagInRangeEvent(Interface* self) { | ||
| 93 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 94 | |||
| 95 | cmd_buff[0] = IPC::MakeHeader(0xB, 1, 2); | ||
| 96 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 97 | cmd_buff[2] = IPC::CopyHandleDesc(); | ||
| 98 | cmd_buff[3] = Kernel::g_handle_table.Create(tag_in_range_event).Unwrap(); | ||
| 99 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 100 | } | ||
| 101 | |||
| 102 | void GetTagOutOfRangeEvent(Interface* self) { | ||
| 103 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 104 | |||
| 105 | cmd_buff[0] = IPC::MakeHeader(0xC, 1, 2); | ||
| 106 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 107 | cmd_buff[2] = IPC::CopyHandleDesc(); | ||
| 108 | cmd_buff[3] = Kernel::g_handle_table.Create(tag_out_of_range_event).Unwrap(); | ||
| 109 | LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||
| 110 | } | ||
| 111 | |||
| 112 | void GetTagState(Interface* self) { | ||
| 113 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 114 | |||
| 115 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 116 | cmd_buff[2] = static_cast<u8>(nfc_tag_state); | ||
| 117 | LOG_DEBUG(Service_NFC, "(STUBBED) called"); | ||
| 118 | } | ||
| 119 | |||
| 120 | void CommunicationGetStatus(Interface* self) { | ||
| 121 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 122 | |||
| 123 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 124 | cmd_buff[2] = static_cast<u8>(nfc_status); | ||
| 125 | LOG_DEBUG(Service_NFC, "(STUBBED) called"); | ||
| 126 | } | ||
| 127 | |||
| 128 | void Init() { | ||
| 129 | AddService(new NFC_M()); | ||
| 130 | AddService(new NFC_U()); | ||
| 131 | |||
| 132 | tag_in_range_event = | ||
| 133 | Kernel::Event::Create(Kernel::ResetType::OneShot, "NFC::tag_in_range_event"); | ||
| 134 | tag_out_of_range_event = | ||
| 135 | Kernel::Event::Create(Kernel::ResetType::OneShot, "NFC::tag_out_range_event"); | ||
| 136 | nfc_tag_state = TagState::NotInitialized; | ||
| 137 | } | ||
| 138 | |||
| 139 | void Shutdown() { | ||
| 140 | tag_in_range_event = nullptr; | ||
| 141 | tag_out_of_range_event = nullptr; | ||
| 142 | } | ||
| 143 | |||
| 144 | } // namespace NFC | ||
| 145 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h deleted file mode 100644 index a013bdae7..000000000 --- a/src/core/hle/service/nfc/nfc.h +++ /dev/null | |||
| @@ -1,153 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | |||
| 11 | class Interface; | ||
| 12 | |||
| 13 | namespace NFC { | ||
| 14 | |||
| 15 | enum class TagState : u8 { | ||
| 16 | NotInitialized = 0, | ||
| 17 | NotScanning = 1, | ||
| 18 | Scanning = 2, | ||
| 19 | TagInRange = 3, | ||
| 20 | TagOutOfRange = 4, | ||
| 21 | TagDataLoaded = 5, | ||
| 22 | }; | ||
| 23 | |||
| 24 | enum class CommunicationStatus : u8 { | ||
| 25 | AttemptInitialize = 1, | ||
| 26 | NfcInitialized = 2, | ||
| 27 | }; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * NFC::Initialize service function | ||
| 31 | * Inputs: | ||
| 32 | * 0 : Header code [0x00010040] | ||
| 33 | * 1 : (u8) unknown parameter. Can be either value 0x1 or 0x2 | ||
| 34 | * Outputs: | ||
| 35 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 36 | */ | ||
| 37 | void Initialize(Interface* self); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * NFC::Shutdown service function | ||
| 41 | * Inputs: | ||
| 42 | * 0 : Header code [0x00020040] | ||
| 43 | * 1 : (u8) unknown parameter | ||
| 44 | * Outputs: | ||
| 45 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 46 | */ | ||
| 47 | void Shutdown(Interface* self); | ||
| 48 | |||
| 49 | /** | ||
| 50 | * NFC::StartCommunication service function | ||
| 51 | * Inputs: | ||
| 52 | * 0 : Header code [0x00030000] | ||
| 53 | * Outputs: | ||
| 54 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 55 | */ | ||
| 56 | void StartCommunication(Interface* self); | ||
| 57 | |||
| 58 | /** | ||
| 59 | * NFC::StopCommunication service function | ||
| 60 | * Inputs: | ||
| 61 | * 0 : Header code [0x00040000] | ||
| 62 | * Outputs: | ||
| 63 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 64 | */ | ||
| 65 | void StopCommunication(Interface* self); | ||
| 66 | |||
| 67 | /** | ||
| 68 | * NFC::StartTagScanning service function | ||
| 69 | * Inputs: | ||
| 70 | * 0 : Header code [0x00050040] | ||
| 71 | * 1 : (u16) unknown. This is normally 0x0 | ||
| 72 | * Outputs: | ||
| 73 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 74 | */ | ||
| 75 | void StartTagScanning(Interface* self); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * NFC::StopTagScanning service function | ||
| 79 | * Inputs: | ||
| 80 | * 0 : Header code [0x00060000] | ||
| 81 | * Outputs: | ||
| 82 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 83 | */ | ||
| 84 | void StopTagScanning(Interface* self); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * NFC::LoadAmiiboData service function | ||
| 88 | * Inputs: | ||
| 89 | * 0 : Header code [0x00070000] | ||
| 90 | * Outputs: | ||
| 91 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 92 | */ | ||
| 93 | void LoadAmiiboData(Interface* self); | ||
| 94 | |||
| 95 | /** | ||
| 96 | * NFC::ResetTagScanState service function | ||
| 97 | * Inputs: | ||
| 98 | * 0 : Header code [0x00080000] | ||
| 99 | * Outputs: | ||
| 100 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 101 | */ | ||
| 102 | void ResetTagScanState(Interface* self); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * NFC::GetTagInRangeEvent service function | ||
| 106 | * Inputs: | ||
| 107 | * 0 : Header code [0x000B0000] | ||
| 108 | * Outputs: | ||
| 109 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 110 | * 2 : Copy handle descriptor | ||
| 111 | * 3 : Event Handle | ||
| 112 | */ | ||
| 113 | void GetTagInRangeEvent(Interface* self); | ||
| 114 | |||
| 115 | /** | ||
| 116 | * NFC::GetTagOutOfRangeEvent service function | ||
| 117 | * Inputs: | ||
| 118 | * 0 : Header code [0x000C0000] | ||
| 119 | * Outputs: | ||
| 120 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 121 | * 2 : Copy handle descriptor | ||
| 122 | * 3 : Event Handle | ||
| 123 | */ | ||
| 124 | void GetTagOutOfRangeEvent(Interface* self); | ||
| 125 | |||
| 126 | /** | ||
| 127 | * NFC::GetTagState service function | ||
| 128 | * Inputs: | ||
| 129 | * 0 : Header code [0x000D0000] | ||
| 130 | * Outputs: | ||
| 131 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 132 | * 2 : (u8) Tag state | ||
| 133 | */ | ||
| 134 | void GetTagState(Interface* self); | ||
| 135 | |||
| 136 | /** | ||
| 137 | * NFC::CommunicationGetStatus service function | ||
| 138 | * Inputs: | ||
| 139 | * 0 : Header code [0x000F0000] | ||
| 140 | * Outputs: | ||
| 141 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 142 | * 2 : (u8) Communication state | ||
| 143 | */ | ||
| 144 | void CommunicationGetStatus(Interface* self); | ||
| 145 | |||
| 146 | /// Initialize all NFC services. | ||
| 147 | void Init(); | ||
| 148 | |||
| 149 | /// Shutdown all NFC services. | ||
| 150 | void Shutdown(); | ||
| 151 | |||
| 152 | } // namespace NFC | ||
| 153 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp deleted file mode 100644 index ebe637650..000000000 --- a/src/core/hle/service/nfc/nfc_m.cpp +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nfc/nfc.h" | ||
| 6 | #include "core/hle/service/nfc/nfc_m.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NFC { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // clang-format off | ||
| 13 | // nfc:u shared commands | ||
| 14 | {0x00010040, Initialize, "Initialize"}, | ||
| 15 | {0x00020040, Shutdown, "Shutdown"}, | ||
| 16 | {0x00030000, StartCommunication, "StartCommunication"}, | ||
| 17 | {0x00040000, StopCommunication, "StopCommunication"}, | ||
| 18 | {0x00050040, StartTagScanning, "StartTagScanning"}, | ||
| 19 | {0x00060000, StopTagScanning, "StopTagScanning"}, | ||
| 20 | {0x00070000, LoadAmiiboData, "LoadAmiiboData"}, | ||
| 21 | {0x00080000, ResetTagScanState, "ResetTagScanState"}, | ||
| 22 | {0x00090002, nullptr, "UpdateStoredAmiiboData"}, | ||
| 23 | {0x000B0000, GetTagInRangeEvent, "GetTagInRangeEvent"}, | ||
| 24 | {0x000C0000, GetTagOutOfRangeEvent, "GetTagOutOfRangeEvent"}, | ||
| 25 | {0x000D0000, GetTagState, "GetTagState"}, | ||
| 26 | {0x000F0000, CommunicationGetStatus, "CommunicationGetStatus"}, | ||
| 27 | {0x00100000, nullptr, "GetTagInfo2"}, | ||
| 28 | {0x00110000, nullptr, "GetTagInfo"}, | ||
| 29 | {0x00120000, nullptr, "CommunicationGetResult"}, | ||
| 30 | {0x00130040, nullptr, "OpenAppData"}, | ||
| 31 | {0x00140384, nullptr, "InitializeWriteAppData"}, | ||
| 32 | {0x00150040, nullptr, "ReadAppData"}, | ||
| 33 | {0x00160242, nullptr, "WriteAppData"}, | ||
| 34 | {0x00170000, nullptr, "GetAmiiboSettings"}, | ||
| 35 | {0x00180000, nullptr, "GetAmiiboConfig"}, | ||
| 36 | {0x00190000, nullptr, "GetAppDataInitStruct"}, | ||
| 37 | // nfc:m | ||
| 38 | {0x04040A40, nullptr, "SetAmiiboSettings"} | ||
| 39 | // clang-format on | ||
| 40 | }; | ||
| 41 | |||
| 42 | NFC_M::NFC_M() { | ||
| 43 | Register(FunctionTable); | ||
| 44 | } | ||
| 45 | |||
| 46 | } // namespace NFC | ||
| 47 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc_m.h b/src/core/hle/service/nfc/nfc_m.h deleted file mode 100644 index fae75535b..000000000 --- a/src/core/hle/service/nfc/nfc_m.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NFC { | ||
| 11 | |||
| 12 | class NFC_M final : public Interface { | ||
| 13 | public: | ||
| 14 | NFC_M(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nfc:m"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NFC | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp deleted file mode 100644 index 5a40c7874..000000000 --- a/src/core/hle/service/nfc/nfc_u.cpp +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nfc/nfc.h" | ||
| 6 | #include "core/hle/service/nfc/nfc_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NFC { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // clang-format off | ||
| 13 | {0x00010040, Initialize, "Initialize"}, | ||
| 14 | {0x00020040, Shutdown, "Shutdown"}, | ||
| 15 | {0x00030000, StartCommunication, "StartCommunication"}, | ||
| 16 | {0x00040000, StopCommunication, "StopCommunication"}, | ||
| 17 | {0x00050040, StartTagScanning, "StartTagScanning"}, | ||
| 18 | {0x00060000, StopTagScanning, "StopTagScanning"}, | ||
| 19 | {0x00070000, LoadAmiiboData, "LoadAmiiboData"}, | ||
| 20 | {0x00080000, ResetTagScanState, "ResetTagScanState"}, | ||
| 21 | {0x00090002, nullptr, "UpdateStoredAmiiboData"}, | ||
| 22 | {0x000B0000, GetTagInRangeEvent, "GetTagInRangeEvent"}, | ||
| 23 | {0x000C0000, GetTagOutOfRangeEvent, "GetTagOutOfRangeEvent"}, | ||
| 24 | {0x000D0000, GetTagState, "GetTagState"}, | ||
| 25 | {0x000F0000, CommunicationGetStatus, "CommunicationGetStatus"}, | ||
| 26 | {0x00100000, nullptr, "GetTagInfo2"}, | ||
| 27 | {0x00110000, nullptr, "GetTagInfo"}, | ||
| 28 | {0x00120000, nullptr, "CommunicationGetResult"}, | ||
| 29 | {0x00130040, nullptr, "OpenAppData"}, | ||
| 30 | {0x00140384, nullptr, "InitializeWriteAppData"}, | ||
| 31 | {0x00150040, nullptr, "ReadAppData"}, | ||
| 32 | {0x00160242, nullptr, "WriteAppData"}, | ||
| 33 | {0x00170000, nullptr, "GetAmiiboSettings"}, | ||
| 34 | {0x00180000, nullptr, "GetAmiiboConfig"}, | ||
| 35 | {0x00190000, nullptr, "GetAppDataInitStruct"}, | ||
| 36 | // clang-format on | ||
| 37 | }; | ||
| 38 | |||
| 39 | NFC_U::NFC_U() { | ||
| 40 | Register(FunctionTable); | ||
| 41 | } | ||
| 42 | |||
| 43 | } // namespace NFC | ||
| 44 | } // namespace Service | ||
diff --git a/src/core/hle/service/nfc/nfc_u.h b/src/core/hle/service/nfc/nfc_u.h deleted file mode 100644 index eb7507314..000000000 --- a/src/core/hle/service/nfc/nfc_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NFC { | ||
| 11 | |||
| 12 | class NFC_U final : public Interface { | ||
| 13 | public: | ||
| 14 | NFC_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nfc:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NFC | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp deleted file mode 100644 index b10d5852b..000000000 --- a/src/core/hle/service/nim/nim.cpp +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/hle/ipc.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/kernel/event.h" | ||
| 10 | #include "core/hle/service/nim/nim.h" | ||
| 11 | #include "core/hle/service/nim/nim_aoc.h" | ||
| 12 | #include "core/hle/service/nim/nim_s.h" | ||
| 13 | #include "core/hle/service/nim/nim_u.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace NIM { | ||
| 18 | |||
| 19 | static Kernel::SharedPtr<Kernel::Event> nim_system_update_event; | ||
| 20 | |||
| 21 | void CheckForSysUpdateEvent(Service::Interface* self) { | ||
| 22 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 0, 0); // 0x50000 | ||
| 23 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 24 | rb.Push(RESULT_SUCCESS); | ||
| 25 | rb.PushCopyHandles(Kernel::g_handle_table.Create(nim_system_update_event).Unwrap()); | ||
| 26 | LOG_TRACE(Service_NIM, "called"); | ||
| 27 | } | ||
| 28 | |||
| 29 | void CheckSysUpdateAvailable(Service::Interface* self) { | ||
| 30 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 31 | |||
| 32 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 33 | cmd_buff[2] = 0; // No update available | ||
| 34 | |||
| 35 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 36 | } | ||
| 37 | |||
| 38 | void Init() { | ||
| 39 | using namespace Kernel; | ||
| 40 | |||
| 41 | AddService(new NIM_AOC_Interface); | ||
| 42 | AddService(new NIM_S_Interface); | ||
| 43 | AddService(new NIM_U_Interface); | ||
| 44 | |||
| 45 | nim_system_update_event = Kernel::Event::Create(ResetType::OneShot, "NIM System Update Event"); | ||
| 46 | } | ||
| 47 | |||
| 48 | void Shutdown() { | ||
| 49 | nim_system_update_event = nullptr; | ||
| 50 | } | ||
| 51 | |||
| 52 | } // namespace NIM | ||
| 53 | |||
| 54 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h deleted file mode 100644 index dbf605e5a..000000000 --- a/src/core/hle/service/nim/nim.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | |||
| 9 | class Interface; | ||
| 10 | |||
| 11 | namespace NIM { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * NIM::CheckForSysUpdateEvent service function | ||
| 15 | * Inputs: | ||
| 16 | * 1 : None | ||
| 17 | * Outputs: | ||
| 18 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 19 | * 2 : Copy handle descriptor | ||
| 20 | * 3 : System Update event handle | ||
| 21 | */ | ||
| 22 | void CheckForSysUpdateEvent(Service::Interface* self); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * NIM::CheckSysUpdateAvailable service function | ||
| 26 | * Inputs: | ||
| 27 | * 1 : None | ||
| 28 | * Outputs: | ||
| 29 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 30 | * 2 : flag, 0 = no system update available, 1 = system update available. | ||
| 31 | */ | ||
| 32 | void CheckSysUpdateAvailable(Service::Interface* self); | ||
| 33 | |||
| 34 | /// Initialize NIM service(s) | ||
| 35 | void Init(); | ||
| 36 | |||
| 37 | /// Shutdown NIM service(s) | ||
| 38 | void Shutdown(); | ||
| 39 | |||
| 40 | } // namespace NIM | ||
| 41 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp deleted file mode 100644 index 2d0fb6fc4..000000000 --- a/src/core/hle/service/nim/nim_aoc.cpp +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nim/nim_aoc.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NIM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x00030042, nullptr, "SetApplicationId"}, | ||
| 12 | {0x00040042, nullptr, "SetTin"}, | ||
| 13 | {0x000902D0, nullptr, "ListContentSetsEx"}, | ||
| 14 | {0x00180000, nullptr, "GetBalance"}, | ||
| 15 | {0x001D0000, nullptr, "GetCustomerSupportCode"}, | ||
| 16 | {0x00210000, nullptr, "Initialize"}, | ||
| 17 | {0x00240282, nullptr, "CalculateContentsRequiredSize"}, | ||
| 18 | {0x00250000, nullptr, "RefreshServerTime"}, | ||
| 19 | }; | ||
| 20 | |||
| 21 | NIM_AOC_Interface::NIM_AOC_Interface() { | ||
| 22 | Register(FunctionTable); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // namespace NIM | ||
| 26 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h deleted file mode 100644 index aace45b5a..000000000 --- a/src/core/hle/service/nim/nim_aoc.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NIM { | ||
| 11 | |||
| 12 | class NIM_AOC_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NIM_AOC_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nim:aoc"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NIM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp deleted file mode 100644 index 28b87e6f7..000000000 --- a/src/core/hle/service/nim/nim_s.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nim/nim_s.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NIM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, | ||
| 12 | {0x0016020A, nullptr, "ListTitles"}, | ||
| 13 | {0x00290000, nullptr, "AccountCheckBalanceSOAP"}, | ||
| 14 | {0x002D0042, nullptr, "DownloadTickets"}, | ||
| 15 | {0x00420240, nullptr, "StartDownload"}, | ||
| 16 | }; | ||
| 17 | |||
| 18 | NIM_S_Interface::NIM_S_Interface() { | ||
| 19 | Register(FunctionTable); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace NIM | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h deleted file mode 100644 index f4bf73d26..000000000 --- a/src/core/hle/service/nim/nim_s.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included.. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NIM { | ||
| 11 | |||
| 12 | class NIM_S_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NIM_S_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nim:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NIM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp deleted file mode 100644 index 569660278..000000000 --- a/src/core/hle/service/nim/nim_u.cpp +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nim/nim.h" | ||
| 6 | #include "core/hle/service/nim/nim_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NIM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010000, nullptr, "StartSysUpdate"}, | ||
| 13 | {0x00020000, nullptr, "GetUpdateDownloadProgress"}, | ||
| 14 | {0x00040000, nullptr, "FinishTitlesInstall"}, | ||
| 15 | {0x00050000, CheckForSysUpdateEvent, "CheckForSysUpdateEvent"}, | ||
| 16 | {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, | ||
| 17 | {0x000A0000, nullptr, "GetState"}, | ||
| 18 | {0x000B0000, nullptr, "GetSystemTitleHash"}, | ||
| 19 | }; | ||
| 20 | |||
| 21 | NIM_U_Interface::NIM_U_Interface() { | ||
| 22 | Register(FunctionTable); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // namespace NIM | ||
| 26 | } // namespace Service | ||
diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h deleted file mode 100644 index c4b74985a..000000000 --- a/src/core/hle/service/nim/nim_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NIM { | ||
| 11 | |||
| 12 | class NIM_U_Interface : public Service::Interface { | ||
| 13 | public: | ||
| 14 | NIM_U_Interface(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nim:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NIM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm.cpp b/src/core/hle/service/nwm/nwm.cpp deleted file mode 100644 index 9f1994dc3..000000000 --- a/src/core/hle/service/nwm/nwm.cpp +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm.h" | ||
| 6 | #include "core/hle/service/nwm/nwm_cec.h" | ||
| 7 | #include "core/hle/service/nwm/nwm_ext.h" | ||
| 8 | #include "core/hle/service/nwm/nwm_inf.h" | ||
| 9 | #include "core/hle/service/nwm/nwm_sap.h" | ||
| 10 | #include "core/hle/service/nwm/nwm_soc.h" | ||
| 11 | #include "core/hle/service/nwm/nwm_tst.h" | ||
| 12 | #include "core/hle/service/nwm/nwm_uds.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace NWM { | ||
| 16 | |||
| 17 | void Init() { | ||
| 18 | AddService(new NWM_CEC); | ||
| 19 | AddService(new NWM_EXT); | ||
| 20 | AddService(new NWM_INF); | ||
| 21 | AddService(new NWM_SAP); | ||
| 22 | AddService(new NWM_SOC); | ||
| 23 | AddService(new NWM_TST); | ||
| 24 | AddService(new NWM_UDS); | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace NWM | ||
| 28 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm.h b/src/core/hle/service/nwm/nwm.h deleted file mode 100644 index 6926b29a6..000000000 --- a/src/core/hle/service/nwm/nwm.h +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | /// Initialize all NWM services | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | } // namespace NWM | ||
| 14 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_cec.cpp b/src/core/hle/service/nwm/nwm_cec.cpp deleted file mode 100644 index 7f03987df..000000000 --- a/src/core/hle/service/nwm/nwm_cec.cpp +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_cec.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x000D0082, nullptr, "SendProbeRequest"}, | ||
| 12 | }; | ||
| 13 | |||
| 14 | NWM_CEC::NWM_CEC() { | ||
| 15 | Register(FunctionTable); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace NWM | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h deleted file mode 100644 index 07b6addb5..000000000 --- a/src/core/hle/service/nwm/nwm_cec.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_CEC final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_CEC(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::CEC"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_ext.cpp b/src/core/hle/service/nwm/nwm_ext.cpp deleted file mode 100644 index 605640a13..000000000 --- a/src/core/hle/service/nwm/nwm_ext.cpp +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_ext.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x00080040, nullptr, "ControlWirelessEnabled"}, | ||
| 12 | }; | ||
| 13 | |||
| 14 | NWM_EXT::NWM_EXT() { | ||
| 15 | Register(FunctionTable); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace NWM | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h deleted file mode 100644 index 51d39d9ea..000000000 --- a/src/core/hle/service/nwm/nwm_ext.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_EXT final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_EXT(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::EXT"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_inf.cpp b/src/core/hle/service/nwm/nwm_inf.cpp deleted file mode 100644 index c8470589b..000000000 --- a/src/core/hle/service/nwm/nwm_inf.cpp +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_inf.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | {0x000603C4, nullptr, "RecvBeaconBroadcastData"}, | ||
| 12 | {0x00070742, nullptr, "ConnectToEncryptedAP"}, | ||
| 13 | {0x00080302, nullptr, "ConnectToAP"}, | ||
| 14 | }; | ||
| 15 | |||
| 16 | NWM_INF::NWM_INF() { | ||
| 17 | Register(FunctionTable); | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace NWM | ||
| 21 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h deleted file mode 100644 index 0043d769c..000000000 --- a/src/core/hle/service/nwm/nwm_inf.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_INF final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_INF(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::INF"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_sap.cpp b/src/core/hle/service/nwm/nwm_sap.cpp deleted file mode 100644 index fd29ed761..000000000 --- a/src/core/hle/service/nwm/nwm_sap.cpp +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_sap.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | /* | ||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | }; | ||
| 13 | */ | ||
| 14 | |||
| 15 | NWM_SAP::NWM_SAP() { | ||
| 16 | // Register(FunctionTable); | ||
| 17 | } | ||
| 18 | |||
| 19 | } // namespace NWM | ||
| 20 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h deleted file mode 100644 index f692e06d4..000000000 --- a/src/core/hle/service/nwm/nwm_sap.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_SAP final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_SAP(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::SAP"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_soc.cpp b/src/core/hle/service/nwm/nwm_soc.cpp deleted file mode 100644 index fdffcb925..000000000 --- a/src/core/hle/service/nwm/nwm_soc.cpp +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_soc.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | /* | ||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | }; | ||
| 13 | */ | ||
| 14 | |||
| 15 | NWM_SOC::NWM_SOC() { | ||
| 16 | // Register(FunctionTable); | ||
| 17 | } | ||
| 18 | |||
| 19 | } // namespace NWM | ||
| 20 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h deleted file mode 100644 index 594941d7e..000000000 --- a/src/core/hle/service/nwm/nwm_soc.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_SOC final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_SOC(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::SOC"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_tst.cpp b/src/core/hle/service/nwm/nwm_tst.cpp deleted file mode 100644 index 5f292e5db..000000000 --- a/src/core/hle/service/nwm/nwm_tst.cpp +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_tst.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace NWM { | ||
| 9 | |||
| 10 | /* | ||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | }; | ||
| 13 | */ | ||
| 14 | |||
| 15 | NWM_TST::NWM_TST() { | ||
| 16 | // Register(FunctionTable); | ||
| 17 | } | ||
| 18 | |||
| 19 | } // namespace NWM | ||
| 20 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h deleted file mode 100644 index 8deca3216..000000000 --- a/src/core/hle/service/nwm/nwm_tst.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | class NWM_TST final : public Interface { | ||
| 13 | public: | ||
| 14 | NWM_TST(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "nwm::TST"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace NWM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp deleted file mode 100644 index 87a6b0eca..000000000 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ /dev/null | |||
| @@ -1,1035 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include <cstring> | ||
| 8 | #include <list> | ||
| 9 | #include <mutex> | ||
| 10 | #include <unordered_map> | ||
| 11 | #include <vector> | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "core/core_timing.h" | ||
| 15 | #include "core/hle/ipc_helpers.h" | ||
| 16 | #include "core/hle/kernel/event.h" | ||
| 17 | #include "core/hle/kernel/shared_memory.h" | ||
| 18 | #include "core/hle/lock.h" | ||
| 19 | #include "core/hle/result.h" | ||
| 20 | #include "core/hle/service/nwm/nwm_uds.h" | ||
| 21 | #include "core/hle/service/nwm/uds_beacon.h" | ||
| 22 | #include "core/hle/service/nwm/uds_connection.h" | ||
| 23 | #include "core/hle/service/nwm/uds_data.h" | ||
| 24 | #include "core/memory.h" | ||
| 25 | #include "network/network.h" | ||
| 26 | |||
| 27 | namespace Service { | ||
| 28 | namespace NWM { | ||
| 29 | |||
| 30 | // Event that is signaled every time the connection status changes. | ||
| 31 | static Kernel::SharedPtr<Kernel::Event> connection_status_event; | ||
| 32 | |||
| 33 | // Shared memory provided by the application to store the receive buffer. | ||
| 34 | // This is not currently used. | ||
| 35 | static Kernel::SharedPtr<Kernel::SharedMemory> recv_buffer_memory; | ||
| 36 | |||
| 37 | // Connection status of this 3DS. | ||
| 38 | static ConnectionStatus connection_status{}; | ||
| 39 | |||
| 40 | /* Node information about the current network. | ||
| 41 | * The amount of elements in this vector is always the maximum number | ||
| 42 | * of nodes specified in the network configuration. | ||
| 43 | * The first node is always the host. | ||
| 44 | */ | ||
| 45 | static NodeList node_info; | ||
| 46 | |||
| 47 | // Node information about our own system. | ||
| 48 | static NodeInfo current_node; | ||
| 49 | |||
| 50 | // Mapping of bind node ids to their respective events. | ||
| 51 | static std::unordered_map<u32, Kernel::SharedPtr<Kernel::Event>> bind_node_events; | ||
| 52 | |||
| 53 | // The WiFi network channel that the network is currently on. | ||
| 54 | // Since we're not actually interacting with physical radio waves, this is just a dummy value. | ||
| 55 | static u8 network_channel = DefaultNetworkChannel; | ||
| 56 | |||
| 57 | // Information about the network that we're currently connected to. | ||
| 58 | static NetworkInfo network_info; | ||
| 59 | |||
| 60 | // Event that will generate and send the 802.11 beacon frames. | ||
| 61 | static int beacon_broadcast_event; | ||
| 62 | |||
| 63 | // Mutex to synchronize access to the connection status between the emulation thread and the | ||
| 64 | // network thread. | ||
| 65 | static std::mutex connection_status_mutex; | ||
| 66 | |||
| 67 | // Mutex to synchronize access to the list of received beacons between the emulation thread and the | ||
| 68 | // network thread. | ||
| 69 | static std::mutex beacon_mutex; | ||
| 70 | |||
| 71 | // Number of beacons to store before we start dropping the old ones. | ||
| 72 | // TODO(Subv): Find a more accurate value for this limit. | ||
| 73 | constexpr size_t MaxBeaconFrames = 15; | ||
| 74 | |||
| 75 | // List of the last <MaxBeaconFrames> beacons received from the network. | ||
| 76 | static std::list<Network::WifiPacket> received_beacons; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Returns a list of received 802.11 beacon frames from the specified sender since the last call. | ||
| 80 | */ | ||
| 81 | std::list<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) { | ||
| 82 | std::lock_guard<std::mutex> lock(beacon_mutex); | ||
| 83 | if (sender != Network::BroadcastMac) { | ||
| 84 | std::list<Network::WifiPacket> filtered_list; | ||
| 85 | const auto beacon = std::find_if(received_beacons.begin(), received_beacons.end(), | ||
| 86 | [&sender](const Network::WifiPacket& packet) { | ||
| 87 | return packet.transmitter_address == sender; | ||
| 88 | }); | ||
| 89 | if (beacon != received_beacons.end()) { | ||
| 90 | filtered_list.push_back(*beacon); | ||
| 91 | // TODO(B3N30): Check if the complete deque is cleared or just the fetched entries | ||
| 92 | received_beacons.erase(beacon); | ||
| 93 | } | ||
| 94 | return filtered_list; | ||
| 95 | } | ||
| 96 | return std::move(received_beacons); | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Sends a WifiPacket to the room we're currently connected to. | ||
| 100 | void SendPacket(Network::WifiPacket& packet) { | ||
| 101 | // TODO(Subv): Implement. | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Returns an available index in the nodes array for the | ||
| 106 | * currently-hosted UDS network. | ||
| 107 | */ | ||
| 108 | static u16 GetNextAvailableNodeId() { | ||
| 109 | for (u16 index = 0; index < connection_status.max_nodes; ++index) { | ||
| 110 | if ((connection_status.node_bitmask & (1 << index)) == 0) | ||
| 111 | return index; | ||
| 112 | } | ||
| 113 | |||
| 114 | // Any connection attempts to an already full network should have been refused. | ||
| 115 | ASSERT_MSG(false, "No available connection slots in the network"); | ||
| 116 | } | ||
| 117 | |||
| 118 | // Inserts the received beacon frame in the beacon queue and removes any older beacons if the size | ||
| 119 | // limit is exceeded. | ||
| 120 | void HandleBeaconFrame(const Network::WifiPacket& packet) { | ||
| 121 | std::lock_guard<std::mutex> lock(beacon_mutex); | ||
| 122 | const auto unique_beacon = | ||
| 123 | std::find_if(received_beacons.begin(), received_beacons.end(), | ||
| 124 | [&packet](const Network::WifiPacket& new_packet) { | ||
| 125 | return new_packet.transmitter_address == packet.transmitter_address; | ||
| 126 | }); | ||
| 127 | if (unique_beacon != received_beacons.end()) { | ||
| 128 | // We already have a beacon from the same mac in the deque, remove the old one; | ||
| 129 | received_beacons.erase(unique_beacon); | ||
| 130 | } | ||
| 131 | |||
| 132 | received_beacons.emplace_back(packet); | ||
| 133 | |||
| 134 | // Discard old beacons if the buffer is full. | ||
| 135 | if (received_beacons.size() > MaxBeaconFrames) | ||
| 136 | received_beacons.pop_front(); | ||
| 137 | } | ||
| 138 | |||
| 139 | void HandleAssociationResponseFrame(const Network::WifiPacket& packet) { | ||
| 140 | auto assoc_result = GetAssociationResult(packet.data); | ||
| 141 | |||
| 142 | ASSERT_MSG(std::get<AssocStatus>(assoc_result) == AssocStatus::Successful, | ||
| 143 | "Could not join network"); | ||
| 144 | { | ||
| 145 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 146 | ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::Connecting)); | ||
| 147 | } | ||
| 148 | |||
| 149 | // Send the EAPoL-Start packet to the server. | ||
| 150 | using Network::WifiPacket; | ||
| 151 | WifiPacket eapol_start; | ||
| 152 | eapol_start.channel = network_channel; | ||
| 153 | eapol_start.data = GenerateEAPoLStartFrame(std::get<u16>(assoc_result), current_node); | ||
| 154 | // TODO(B3N30): Encrypt the packet. | ||
| 155 | eapol_start.destination_address = packet.transmitter_address; | ||
| 156 | eapol_start.type = WifiPacket::PacketType::Data; | ||
| 157 | |||
| 158 | SendPacket(eapol_start); | ||
| 159 | } | ||
| 160 | |||
| 161 | static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||
| 162 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 163 | |||
| 164 | if (GetEAPoLFrameType(packet.data) == EAPoLStartMagic) { | ||
| 165 | if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||
| 166 | LOG_DEBUG(Service_NWM, "Connection sequence aborted, because connection status is %u", | ||
| 167 | connection_status.status); | ||
| 168 | return; | ||
| 169 | } | ||
| 170 | |||
| 171 | auto node = DeserializeNodeInfoFromFrame(packet.data); | ||
| 172 | |||
| 173 | if (connection_status.max_nodes == connection_status.total_nodes) { | ||
| 174 | // Reject connection attempt | ||
| 175 | LOG_ERROR(Service_NWM, "Reached maximum nodes, but reject packet wasn't sent."); | ||
| 176 | // TODO(B3N30): Figure out what packet is sent here | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | |||
| 180 | // Get an unused network node id | ||
| 181 | u16 node_id = GetNextAvailableNodeId(); | ||
| 182 | node.network_node_id = node_id + 1; | ||
| 183 | |||
| 184 | connection_status.node_bitmask |= 1 << node_id; | ||
| 185 | connection_status.changed_nodes |= 1 << node_id; | ||
| 186 | connection_status.nodes[node_id] = node.network_node_id; | ||
| 187 | connection_status.total_nodes++; | ||
| 188 | |||
| 189 | u8 current_nodes = network_info.total_nodes; | ||
| 190 | node_info[current_nodes] = node; | ||
| 191 | |||
| 192 | network_info.total_nodes++; | ||
| 193 | |||
| 194 | // Send the EAPoL-Logoff packet. | ||
| 195 | using Network::WifiPacket; | ||
| 196 | WifiPacket eapol_logoff; | ||
| 197 | eapol_logoff.channel = network_channel; | ||
| 198 | eapol_logoff.data = | ||
| 199 | GenerateEAPoLLogoffFrame(packet.transmitter_address, node.network_node_id, node_info, | ||
| 200 | network_info.max_nodes, network_info.total_nodes); | ||
| 201 | // TODO(Subv): Encrypt the packet. | ||
| 202 | eapol_logoff.destination_address = packet.transmitter_address; | ||
| 203 | eapol_logoff.type = WifiPacket::PacketType::Data; | ||
| 204 | |||
| 205 | SendPacket(eapol_logoff); | ||
| 206 | // TODO(B3N30): Broadcast updated node list | ||
| 207 | // The 3ds does this presumably to support spectators. | ||
| 208 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 209 | connection_status_event->Signal(); | ||
| 210 | } else { | ||
| 211 | if (connection_status.status != static_cast<u32>(NetworkStatus::NotConnected)) { | ||
| 212 | LOG_DEBUG(Service_NWM, "Connection sequence aborted, because connection status is %u", | ||
| 213 | connection_status.status); | ||
| 214 | return; | ||
| 215 | } | ||
| 216 | auto logoff = ParseEAPoLLogoffFrame(packet.data); | ||
| 217 | |||
| 218 | network_info.total_nodes = logoff.connected_nodes; | ||
| 219 | network_info.max_nodes = logoff.max_nodes; | ||
| 220 | |||
| 221 | connection_status.network_node_id = logoff.assigned_node_id; | ||
| 222 | connection_status.total_nodes = logoff.connected_nodes; | ||
| 223 | connection_status.max_nodes = logoff.max_nodes; | ||
| 224 | |||
| 225 | node_info.clear(); | ||
| 226 | node_info.reserve(network_info.max_nodes); | ||
| 227 | for (size_t index = 0; index < logoff.connected_nodes; ++index) { | ||
| 228 | connection_status.node_bitmask |= 1 << index; | ||
| 229 | connection_status.changed_nodes |= 1 << index; | ||
| 230 | connection_status.nodes[index] = logoff.nodes[index].network_node_id; | ||
| 231 | |||
| 232 | node_info.emplace_back(DeserializeNodeInfo(logoff.nodes[index])); | ||
| 233 | } | ||
| 234 | |||
| 235 | // We're now connected, signal the application | ||
| 236 | connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsClient); | ||
| 237 | // Some games require ConnectToNetwork to block, for now it doesn't | ||
| 238 | // If blocking is implemented this lock needs to be changed, | ||
| 239 | // otherwise it might cause deadlocks | ||
| 240 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||
| 241 | connection_status_event->Signal(); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11 | ||
| 247 | * authentication frame with SEQ1. | ||
| 248 | */ | ||
| 249 | void StartConnectionSequence(const MacAddress& server) { | ||
| 250 | using Network::WifiPacket; | ||
| 251 | WifiPacket auth_request; | ||
| 252 | { | ||
| 253 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 254 | ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected)); | ||
| 255 | |||
| 256 | // TODO(Subv): Handle timeout. | ||
| 257 | |||
| 258 | // Send an authentication frame with SEQ1 | ||
| 259 | auth_request.channel = network_channel; | ||
| 260 | auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1); | ||
| 261 | auth_request.destination_address = server; | ||
| 262 | auth_request.type = WifiPacket::PacketType::Authentication; | ||
| 263 | } | ||
| 264 | |||
| 265 | SendPacket(auth_request); | ||
| 266 | } | ||
| 267 | |||
| 268 | /// Sends an Association Response frame to the specified mac address | ||
| 269 | void SendAssociationResponseFrame(const MacAddress& address) { | ||
| 270 | using Network::WifiPacket; | ||
| 271 | WifiPacket assoc_response; | ||
| 272 | |||
| 273 | { | ||
| 274 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 275 | if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||
| 276 | LOG_ERROR(Service_NWM, "Connection sequence aborted, because connection status is %u", | ||
| 277 | connection_status.status); | ||
| 278 | return; | ||
| 279 | } | ||
| 280 | |||
| 281 | assoc_response.channel = network_channel; | ||
| 282 | // TODO(Subv): This will cause multiple clients to end up with the same association id, but | ||
| 283 | // we're not using that for anything. | ||
| 284 | u16 association_id = 1; | ||
| 285 | assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id, | ||
| 286 | network_info.network_id); | ||
| 287 | assoc_response.destination_address = address; | ||
| 288 | assoc_response.type = WifiPacket::PacketType::AssociationResponse; | ||
| 289 | } | ||
| 290 | |||
| 291 | SendPacket(assoc_response); | ||
| 292 | } | ||
| 293 | |||
| 294 | /* | ||
| 295 | * Handles the authentication request frame and sends the authentication response and association | ||
| 296 | * response frames. Once an Authentication frame with SEQ1 is received by the server, it responds | ||
| 297 | * with an Authentication frame containing SEQ2, and immediately sends an Association response frame | ||
| 298 | * containing the details of the access point and the assigned association id for the new client. | ||
| 299 | */ | ||
| 300 | void HandleAuthenticationFrame(const Network::WifiPacket& packet) { | ||
| 301 | // Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior | ||
| 302 | if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) { | ||
| 303 | using Network::WifiPacket; | ||
| 304 | WifiPacket auth_request; | ||
| 305 | { | ||
| 306 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 307 | if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||
| 308 | LOG_ERROR(Service_NWM, | ||
| 309 | "Connection sequence aborted, because connection status is %u", | ||
| 310 | connection_status.status); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | // Respond with an authentication response frame with SEQ2 | ||
| 315 | auth_request.channel = network_channel; | ||
| 316 | auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2); | ||
| 317 | auth_request.destination_address = packet.transmitter_address; | ||
| 318 | auth_request.type = WifiPacket::PacketType::Authentication; | ||
| 319 | } | ||
| 320 | SendPacket(auth_request); | ||
| 321 | |||
| 322 | SendAssociationResponseFrame(packet.transmitter_address); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | static void HandleDataFrame(const Network::WifiPacket& packet) { | ||
| 327 | switch (GetFrameEtherType(packet.data)) { | ||
| 328 | case EtherType::EAPoL: | ||
| 329 | HandleEAPoLPacket(packet); | ||
| 330 | break; | ||
| 331 | case EtherType::SecureData: | ||
| 332 | // TODO(B3N30): Handle SecureData packets | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Callback to parse and handle a received wifi packet. | ||
| 338 | void OnWifiPacketReceived(const Network::WifiPacket& packet) { | ||
| 339 | switch (packet.type) { | ||
| 340 | case Network::WifiPacket::PacketType::Beacon: | ||
| 341 | HandleBeaconFrame(packet); | ||
| 342 | break; | ||
| 343 | case Network::WifiPacket::PacketType::Authentication: | ||
| 344 | HandleAuthenticationFrame(packet); | ||
| 345 | break; | ||
| 346 | case Network::WifiPacket::PacketType::AssociationResponse: | ||
| 347 | HandleAssociationResponseFrame(packet); | ||
| 348 | break; | ||
| 349 | case Network::WifiPacket::PacketType::Data: | ||
| 350 | HandleDataFrame(packet); | ||
| 351 | break; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | /** | ||
| 356 | * NWM_UDS::Shutdown service function | ||
| 357 | * Inputs: | ||
| 358 | * 1 : None | ||
| 359 | * Outputs: | ||
| 360 | * 0 : Return header | ||
| 361 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 362 | */ | ||
| 363 | static void Shutdown(Interface* self) { | ||
| 364 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 365 | |||
| 366 | // TODO(purpasmart): Verify return header on HW | ||
| 367 | |||
| 368 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 369 | |||
| 370 | LOG_WARNING(Service_NWM, "(STUBBED) called"); | ||
| 371 | } | ||
| 372 | |||
| 373 | /** | ||
| 374 | * NWM_UDS::RecvBeaconBroadcastData service function | ||
| 375 | * Returns the raw beacon data for nearby networks that match the supplied WlanCommId. | ||
| 376 | * Inputs: | ||
| 377 | * 1 : Output buffer max size | ||
| 378 | * 2-3 : Unknown | ||
| 379 | * 4-5 : Host MAC address. | ||
| 380 | * 6-14 : Unused | ||
| 381 | * 15 : WLan Comm Id | ||
| 382 | * 16 : Id | ||
| 383 | * 17 : Value 0 | ||
| 384 | * 18 : Input handle | ||
| 385 | * 19 : (Size<<4) | 12 | ||
| 386 | * 20 : Output buffer ptr | ||
| 387 | * Outputs: | ||
| 388 | * 0 : Return header | ||
| 389 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 390 | */ | ||
| 391 | static void RecvBeaconBroadcastData(Interface* self) { | ||
| 392 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 16, 4); | ||
| 393 | |||
| 394 | u32 out_buffer_size = rp.Pop<u32>(); | ||
| 395 | u32 unk1 = rp.Pop<u32>(); | ||
| 396 | u32 unk2 = rp.Pop<u32>(); | ||
| 397 | |||
| 398 | MacAddress mac_address; | ||
| 399 | rp.PopRaw(mac_address); | ||
| 400 | |||
| 401 | rp.Skip(9, false); | ||
| 402 | |||
| 403 | u32 wlan_comm_id = rp.Pop<u32>(); | ||
| 404 | u32 id = rp.Pop<u32>(); | ||
| 405 | Kernel::Handle input_handle = rp.PopHandle(); | ||
| 406 | |||
| 407 | size_t desc_size; | ||
| 408 | const VAddr out_buffer_ptr = rp.PopMappedBuffer(&desc_size); | ||
| 409 | ASSERT(desc_size == out_buffer_size); | ||
| 410 | |||
| 411 | VAddr current_buffer_pos = out_buffer_ptr; | ||
| 412 | u32 total_size = sizeof(BeaconDataReplyHeader); | ||
| 413 | |||
| 414 | // Retrieve all beacon frames that were received from the desired mac address. | ||
| 415 | auto beacons = GetReceivedBeacons(mac_address); | ||
| 416 | |||
| 417 | BeaconDataReplyHeader data_reply_header{}; | ||
| 418 | data_reply_header.total_entries = static_cast<u32>(beacons.size()); | ||
| 419 | data_reply_header.max_output_size = out_buffer_size; | ||
| 420 | |||
| 421 | Memory::WriteBlock(current_buffer_pos, &data_reply_header, sizeof(BeaconDataReplyHeader)); | ||
| 422 | current_buffer_pos += sizeof(BeaconDataReplyHeader); | ||
| 423 | |||
| 424 | // Write each of the received beacons into the buffer | ||
| 425 | for (const auto& beacon : beacons) { | ||
| 426 | BeaconEntryHeader entry{}; | ||
| 427 | // TODO(Subv): Figure out what this size is used for. | ||
| 428 | entry.unk_size = static_cast<u32>(sizeof(BeaconEntryHeader) + beacon.data.size()); | ||
| 429 | entry.total_size = static_cast<u32>(sizeof(BeaconEntryHeader) + beacon.data.size()); | ||
| 430 | entry.wifi_channel = beacon.channel; | ||
| 431 | entry.header_size = sizeof(BeaconEntryHeader); | ||
| 432 | entry.mac_address = beacon.transmitter_address; | ||
| 433 | |||
| 434 | ASSERT(current_buffer_pos < out_buffer_ptr + out_buffer_size); | ||
| 435 | |||
| 436 | Memory::WriteBlock(current_buffer_pos, &entry, sizeof(BeaconEntryHeader)); | ||
| 437 | current_buffer_pos += sizeof(BeaconEntryHeader); | ||
| 438 | |||
| 439 | Memory::WriteBlock(current_buffer_pos, beacon.data.data(), beacon.data.size()); | ||
| 440 | current_buffer_pos += static_cast<VAddr>(beacon.data.size()); | ||
| 441 | |||
| 442 | total_size += static_cast<u32>(sizeof(BeaconEntryHeader) + beacon.data.size()); | ||
| 443 | } | ||
| 444 | |||
| 445 | // Update the total size in the structure and write it to the buffer again. | ||
| 446 | data_reply_header.total_size = total_size; | ||
| 447 | Memory::WriteBlock(out_buffer_ptr, &data_reply_header, sizeof(BeaconDataReplyHeader)); | ||
| 448 | |||
| 449 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 450 | rb.Push(RESULT_SUCCESS); | ||
| 451 | |||
| 452 | LOG_DEBUG(Service_NWM, "called out_buffer_size=0x%08X, wlan_comm_id=0x%08X, id=0x%08X," | ||
| 453 | "input_handle=0x%08X, out_buffer_ptr=0x%08X, unk1=0x%08X, unk2=0x%08X", | ||
| 454 | out_buffer_size, wlan_comm_id, id, input_handle, out_buffer_ptr, unk1, unk2); | ||
| 455 | } | ||
| 456 | |||
| 457 | /** | ||
| 458 | * NWM_UDS::Initialize service function | ||
| 459 | * Inputs: | ||
| 460 | * 1 : Shared memory size | ||
| 461 | * 2-11 : Input NodeInfo Structure | ||
| 462 | * 12 : 2-byte Version | ||
| 463 | * 13 : Value 0 | ||
| 464 | * 14 : Shared memory handle | ||
| 465 | * Outputs: | ||
| 466 | * 0 : Return header | ||
| 467 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 468 | * 2 : Value 0 | ||
| 469 | * 3 : Output event handle | ||
| 470 | */ | ||
| 471 | static void InitializeWithVersion(Interface* self) { | ||
| 472 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 12, 2); | ||
| 473 | |||
| 474 | u32 sharedmem_size = rp.Pop<u32>(); | ||
| 475 | |||
| 476 | // Update the node information with the data the game gave us. | ||
| 477 | rp.PopRaw(current_node); | ||
| 478 | |||
| 479 | u16 version = rp.Pop<u16>(); | ||
| 480 | |||
| 481 | Kernel::Handle sharedmem_handle = rp.PopHandle(); | ||
| 482 | |||
| 483 | recv_buffer_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(sharedmem_handle); | ||
| 484 | |||
| 485 | ASSERT_MSG(recv_buffer_memory->size == sharedmem_size, "Invalid shared memory size."); | ||
| 486 | |||
| 487 | { | ||
| 488 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 489 | |||
| 490 | // Reset the connection status, it contains all zeros after initialization, | ||
| 491 | // except for the actual status value. | ||
| 492 | connection_status = {}; | ||
| 493 | connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||
| 494 | } | ||
| 495 | |||
| 496 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 497 | rb.Push(RESULT_SUCCESS); | ||
| 498 | rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap()); | ||
| 499 | |||
| 500 | // TODO(Subv): Connect the OnWifiPacketReceived function to the wifi packet received callback of | ||
| 501 | // the room we're currently in. | ||
| 502 | |||
| 503 | LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X", | ||
| 504 | sharedmem_size, version, sharedmem_handle); | ||
| 505 | } | ||
| 506 | |||
| 507 | /** | ||
| 508 | * NWM_UDS::GetConnectionStatus service function. | ||
| 509 | * Returns the connection status structure for the currently open network connection. | ||
| 510 | * This structure contains information about the connection, | ||
| 511 | * like the number of connected nodes, etc. | ||
| 512 | * Inputs: | ||
| 513 | * 0 : Command header. | ||
| 514 | * Outputs: | ||
| 515 | * 0 : Return header | ||
| 516 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 517 | * 2-13 : Channel of the current WiFi network connection. | ||
| 518 | */ | ||
| 519 | static void GetConnectionStatus(Interface* self) { | ||
| 520 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 0, 0); | ||
| 521 | IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); | ||
| 522 | |||
| 523 | rb.Push(RESULT_SUCCESS); | ||
| 524 | { | ||
| 525 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 526 | rb.PushRaw(connection_status); | ||
| 527 | |||
| 528 | // Reset the bitmask of changed nodes after each call to this | ||
| 529 | // function to prevent falsely informing games of outstanding | ||
| 530 | // changes in subsequent calls. | ||
| 531 | // TODO(Subv): Find exactly where the NWM module resets this value. | ||
| 532 | connection_status.changed_nodes = 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | LOG_DEBUG(Service_NWM, "called"); | ||
| 536 | } | ||
| 537 | |||
| 538 | /** | ||
| 539 | * NWM_UDS::Bind service function. | ||
| 540 | * Binds a BindNodeId to a data channel and retrieves a data event. | ||
| 541 | * Inputs: | ||
| 542 | * 1 : BindNodeId | ||
| 543 | * 2 : Receive buffer size. | ||
| 544 | * 3 : u8 Data channel to bind to. | ||
| 545 | * 4 : Network node id. | ||
| 546 | * Outputs: | ||
| 547 | * 0 : Return header | ||
| 548 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 549 | * 2 : Copy handle descriptor. | ||
| 550 | * 3 : Data available event handle. | ||
| 551 | */ | ||
| 552 | static void Bind(Interface* self) { | ||
| 553 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 4, 0); | ||
| 554 | |||
| 555 | u32 bind_node_id = rp.Pop<u32>(); | ||
| 556 | u32 recv_buffer_size = rp.Pop<u32>(); | ||
| 557 | u8 data_channel = rp.Pop<u8>(); | ||
| 558 | u16 network_node_id = rp.Pop<u16>(); | ||
| 559 | |||
| 560 | // TODO(Subv): Store the data channel and verify it when receiving data frames. | ||
| 561 | |||
| 562 | LOG_DEBUG(Service_NWM, "called"); | ||
| 563 | |||
| 564 | if (data_channel == 0) { | ||
| 565 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 566 | rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, | ||
| 567 | ErrorSummary::WrongArgument, ErrorLevel::Usage)); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | |||
| 571 | // Create a new event for this bind node. | ||
| 572 | // TODO(Subv): Signal this event when new data is received on this data channel. | ||
| 573 | auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, | ||
| 574 | "NWM::BindNodeEvent" + std::to_string(bind_node_id)); | ||
| 575 | bind_node_events[bind_node_id] = event; | ||
| 576 | |||
| 577 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 578 | |||
| 579 | rb.Push(RESULT_SUCCESS); | ||
| 580 | rb.PushCopyHandles(Kernel::g_handle_table.Create(event).Unwrap()); | ||
| 581 | } | ||
| 582 | |||
| 583 | /** | ||
| 584 | * NWM_UDS::BeginHostingNetwork service function. | ||
| 585 | * Creates a network and starts broadcasting its presence. | ||
| 586 | * Inputs: | ||
| 587 | * 1 : Passphrase buffer size. | ||
| 588 | * 3 : VAddr of the NetworkInfo structure. | ||
| 589 | * 5 : VAddr of the passphrase. | ||
| 590 | * Outputs: | ||
| 591 | * 0 : Return header | ||
| 592 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 593 | */ | ||
| 594 | static void BeginHostingNetwork(Interface* self) { | ||
| 595 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 1, 4); | ||
| 596 | |||
| 597 | const u32 passphrase_size = rp.Pop<u32>(); | ||
| 598 | |||
| 599 | size_t desc_size; | ||
| 600 | const VAddr network_info_address = rp.PopStaticBuffer(&desc_size, false); | ||
| 601 | ASSERT(desc_size == sizeof(NetworkInfo)); | ||
| 602 | const VAddr passphrase_address = rp.PopStaticBuffer(&desc_size, false); | ||
| 603 | ASSERT(desc_size == passphrase_size); | ||
| 604 | |||
| 605 | // TODO(Subv): Store the passphrase and verify it when attempting a connection. | ||
| 606 | |||
| 607 | LOG_DEBUG(Service_NWM, "called"); | ||
| 608 | |||
| 609 | Memory::ReadBlock(network_info_address, &network_info, sizeof(NetworkInfo)); | ||
| 610 | |||
| 611 | // The real UDS module throws a fatal error if this assert fails. | ||
| 612 | ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member."); | ||
| 613 | |||
| 614 | { | ||
| 615 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 616 | connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost); | ||
| 617 | |||
| 618 | // Ensure the application data size is less than the maximum value. | ||
| 619 | ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, | ||
| 620 | "Data size is too big."); | ||
| 621 | |||
| 622 | // Set up basic information for this network. | ||
| 623 | network_info.oui_value = NintendoOUI; | ||
| 624 | network_info.oui_type = static_cast<u8>(NintendoTagId::NetworkInfo); | ||
| 625 | |||
| 626 | connection_status.max_nodes = network_info.max_nodes; | ||
| 627 | |||
| 628 | // Resize the nodes list to hold max_nodes. | ||
| 629 | node_info.resize(network_info.max_nodes); | ||
| 630 | |||
| 631 | // There's currently only one node in the network (the host). | ||
| 632 | connection_status.total_nodes = 1; | ||
| 633 | network_info.total_nodes = 1; | ||
| 634 | // The host is always the first node | ||
| 635 | connection_status.network_node_id = 1; | ||
| 636 | current_node.network_node_id = 1; | ||
| 637 | connection_status.nodes[0] = connection_status.network_node_id; | ||
| 638 | // Set the bit 0 in the nodes bitmask to indicate that node 1 is already taken. | ||
| 639 | connection_status.node_bitmask |= 1; | ||
| 640 | // Notify the application that the first node was set. | ||
| 641 | connection_status.changed_nodes |= 1; | ||
| 642 | node_info[0] = current_node; | ||
| 643 | } | ||
| 644 | |||
| 645 | // If the game has a preferred channel, use that instead. | ||
| 646 | if (network_info.channel != 0) | ||
| 647 | network_channel = network_info.channel; | ||
| 648 | |||
| 649 | connection_status_event->Signal(); | ||
| 650 | |||
| 651 | // Start broadcasting the network, send a beacon frame every 102.4ms. | ||
| 652 | CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU), | ||
| 653 | beacon_broadcast_event, 0); | ||
| 654 | |||
| 655 | LOG_WARNING(Service_NWM, | ||
| 656 | "An UDS network has been created, but broadcasting it is unimplemented."); | ||
| 657 | |||
| 658 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 659 | rb.Push(RESULT_SUCCESS); | ||
| 660 | } | ||
| 661 | |||
| 662 | /** | ||
| 663 | * NWM_UDS::DestroyNetwork service function. | ||
| 664 | * Closes the network that we're currently hosting. | ||
| 665 | * Inputs: | ||
| 666 | * 0 : Command header. | ||
| 667 | * Outputs: | ||
| 668 | * 0 : Return header | ||
| 669 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 670 | */ | ||
| 671 | static void DestroyNetwork(Interface* self) { | ||
| 672 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 0, 0); | ||
| 673 | |||
| 674 | // TODO(Subv): Find out what happens if this is called while | ||
| 675 | // no network is being hosted. | ||
| 676 | |||
| 677 | // Unschedule the beacon broadcast event. | ||
| 678 | CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); | ||
| 679 | |||
| 680 | { | ||
| 681 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 682 | |||
| 683 | // TODO(Subv): Check if connection_status is indeed reset after this call. | ||
| 684 | connection_status = {}; | ||
| 685 | connection_status.status = static_cast<u8>(NetworkStatus::NotConnected); | ||
| 686 | } | ||
| 687 | connection_status_event->Signal(); | ||
| 688 | |||
| 689 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 690 | |||
| 691 | rb.Push(RESULT_SUCCESS); | ||
| 692 | |||
| 693 | LOG_WARNING(Service_NWM, "called"); | ||
| 694 | } | ||
| 695 | |||
| 696 | /** | ||
| 697 | * NWM_UDS::SendTo service function. | ||
| 698 | * Sends a data frame to the UDS network we're connected to. | ||
| 699 | * Inputs: | ||
| 700 | * 0 : Command header. | ||
| 701 | * 1 : Unknown. | ||
| 702 | * 2 : u16 Destination network node id. | ||
| 703 | * 3 : u8 Data channel. | ||
| 704 | * 4 : Buffer size >> 2 | ||
| 705 | * 5 : Data size | ||
| 706 | * 6 : Flags | ||
| 707 | * 7 : Input buffer descriptor | ||
| 708 | * 8 : Input buffer address | ||
| 709 | * Outputs: | ||
| 710 | * 0 : Return header | ||
| 711 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 712 | */ | ||
| 713 | static void SendTo(Interface* self) { | ||
| 714 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 6, 2); | ||
| 715 | |||
| 716 | rp.Skip(1, false); | ||
| 717 | u16 dest_node_id = rp.Pop<u16>(); | ||
| 718 | u8 data_channel = rp.Pop<u8>(); | ||
| 719 | rp.Skip(1, false); | ||
| 720 | u32 data_size = rp.Pop<u32>(); | ||
| 721 | u32 flags = rp.Pop<u32>(); | ||
| 722 | |||
| 723 | size_t desc_size; | ||
| 724 | const VAddr input_address = rp.PopStaticBuffer(&desc_size, false); | ||
| 725 | ASSERT(desc_size == data_size); | ||
| 726 | |||
| 727 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 728 | |||
| 729 | u16 network_node_id; | ||
| 730 | |||
| 731 | { | ||
| 732 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 733 | if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsClient) && | ||
| 734 | connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||
| 735 | rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, | ||
| 736 | ErrorSummary::InvalidState, ErrorLevel::Status)); | ||
| 737 | return; | ||
| 738 | } | ||
| 739 | |||
| 740 | if (dest_node_id == connection_status.network_node_id) { | ||
| 741 | rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS, | ||
| 742 | ErrorSummary::WrongArgument, ErrorLevel::Status)); | ||
| 743 | return; | ||
| 744 | } | ||
| 745 | |||
| 746 | network_node_id = connection_status.network_node_id; | ||
| 747 | } | ||
| 748 | |||
| 749 | // TODO(Subv): Do something with the flags. | ||
| 750 | |||
| 751 | constexpr size_t MaxSize = 0x5C6; | ||
| 752 | if (data_size > MaxSize) { | ||
| 753 | rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS, | ||
| 754 | ErrorSummary::WrongArgument, ErrorLevel::Usage)); | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | |||
| 758 | std::vector<u8> data(data_size); | ||
| 759 | Memory::ReadBlock(input_address, data.data(), data.size()); | ||
| 760 | |||
| 761 | // TODO(Subv): Increment the sequence number after each sent packet. | ||
| 762 | u16 sequence_number = 0; | ||
| 763 | std::vector<u8> data_payload = | ||
| 764 | GenerateDataPayload(data, data_channel, dest_node_id, network_node_id, sequence_number); | ||
| 765 | |||
| 766 | // TODO(Subv): Retrieve the MAC address of the dest_node_id and our own to encrypt | ||
| 767 | // and encapsulate the payload. | ||
| 768 | |||
| 769 | // TODO(Subv): Send the frame. | ||
| 770 | |||
| 771 | rb.Push(RESULT_SUCCESS); | ||
| 772 | |||
| 773 | LOG_WARNING(Service_NWM, "(STUB) called dest_node_id=%u size=%u flags=%u channel=%u", | ||
| 774 | static_cast<u32>(dest_node_id), data_size, flags, static_cast<u32>(data_channel)); | ||
| 775 | } | ||
| 776 | |||
| 777 | /** | ||
| 778 | * NWM_UDS::GetChannel service function. | ||
| 779 | * Returns the WiFi channel in which the network we're connected to is transmitting. | ||
| 780 | * Inputs: | ||
| 781 | * 0 : Command header. | ||
| 782 | * Outputs: | ||
| 783 | * 0 : Return header | ||
| 784 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 785 | * 2 : Channel of the current WiFi network connection. | ||
| 786 | */ | ||
| 787 | static void GetChannel(Interface* self) { | ||
| 788 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 0, 0); | ||
| 789 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 790 | |||
| 791 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 792 | bool is_connected = connection_status.status != static_cast<u32>(NetworkStatus::NotConnected); | ||
| 793 | |||
| 794 | u8 channel = is_connected ? network_channel : 0; | ||
| 795 | |||
| 796 | rb.Push(RESULT_SUCCESS); | ||
| 797 | rb.Push(channel); | ||
| 798 | |||
| 799 | LOG_DEBUG(Service_NWM, "called"); | ||
| 800 | } | ||
| 801 | |||
| 802 | /** | ||
| 803 | * NWM_UDS::SetApplicationData service function. | ||
| 804 | * Updates the application data that is being broadcast in the beacon frames | ||
| 805 | * for the network that we're hosting. | ||
| 806 | * Inputs: | ||
| 807 | * 1 : Data size. | ||
| 808 | * 3 : VAddr of the data. | ||
| 809 | * Outputs: | ||
| 810 | * 0 : Return header | ||
| 811 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 812 | * 2 : Channel of the current WiFi network connection. | ||
| 813 | */ | ||
| 814 | static void SetApplicationData(Interface* self) { | ||
| 815 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 1, 2); | ||
| 816 | |||
| 817 | u32 size = rp.Pop<u32>(); | ||
| 818 | |||
| 819 | size_t desc_size; | ||
| 820 | const VAddr address = rp.PopStaticBuffer(&desc_size, false); | ||
| 821 | ASSERT(desc_size == size); | ||
| 822 | |||
| 823 | LOG_DEBUG(Service_NWM, "called"); | ||
| 824 | |||
| 825 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 826 | |||
| 827 | if (size > ApplicationDataSize) { | ||
| 828 | rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS, | ||
| 829 | ErrorSummary::WrongArgument, ErrorLevel::Usage)); | ||
| 830 | return; | ||
| 831 | } | ||
| 832 | |||
| 833 | network_info.application_data_size = size; | ||
| 834 | Memory::ReadBlock(address, network_info.application_data.data(), size); | ||
| 835 | |||
| 836 | rb.Push(RESULT_SUCCESS); | ||
| 837 | } | ||
| 838 | |||
| 839 | /** | ||
| 840 | * NWM_UDS::DecryptBeaconData service function. | ||
| 841 | * Decrypts the encrypted data tags contained in the 802.11 beacons. | ||
| 842 | * Inputs: | ||
| 843 | * 1 : Input network struct buffer descriptor. | ||
| 844 | * 2 : Input network struct buffer ptr. | ||
| 845 | * 3 : Input tag0 encrypted buffer descriptor. | ||
| 846 | * 4 : Input tag0 encrypted buffer ptr. | ||
| 847 | * 5 : Input tag1 encrypted buffer descriptor. | ||
| 848 | * 6 : Input tag1 encrypted buffer ptr. | ||
| 849 | * 64 : Output buffer descriptor. | ||
| 850 | * 65 : Output buffer ptr. | ||
| 851 | * Outputs: | ||
| 852 | * 0 : Return header | ||
| 853 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 854 | */ | ||
| 855 | static void DecryptBeaconData(Interface* self) { | ||
| 856 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 0, 6); | ||
| 857 | |||
| 858 | size_t desc_size; | ||
| 859 | const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size); | ||
| 860 | ASSERT(desc_size == sizeof(NetworkInfo)); | ||
| 861 | |||
| 862 | size_t data0_size; | ||
| 863 | const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size); | ||
| 864 | |||
| 865 | size_t data1_size; | ||
| 866 | const VAddr encrypted_data1_addr = rp.PopStaticBuffer(&data1_size); | ||
| 867 | |||
| 868 | size_t output_buffer_size; | ||
| 869 | const VAddr output_buffer_addr = rp.PeekStaticBuffer(0, &output_buffer_size); | ||
| 870 | |||
| 871 | // This size is hardcoded in the 3DS UDS code. | ||
| 872 | ASSERT(output_buffer_size == sizeof(NodeInfo) * UDSMaxNodes); | ||
| 873 | |||
| 874 | LOG_WARNING(Service_NWM, "called in0=%08X in1=%08X out=%08X", encrypted_data0_addr, | ||
| 875 | encrypted_data1_addr, output_buffer_addr); | ||
| 876 | |||
| 877 | NetworkInfo net_info; | ||
| 878 | Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info)); | ||
| 879 | |||
| 880 | // Read the encrypted data. | ||
| 881 | // The first 4 bytes should be the OUI and the OUI Type of the tags. | ||
| 882 | std::array<u8, 3> oui; | ||
| 883 | Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size()); | ||
| 884 | ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); | ||
| 885 | Memory::ReadBlock(encrypted_data1_addr, oui.data(), oui.size()); | ||
| 886 | ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); | ||
| 887 | |||
| 888 | ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) == | ||
| 889 | static_cast<u8>(NintendoTagId::EncryptedData0), | ||
| 890 | "Unexpected tag id"); | ||
| 891 | ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) == | ||
| 892 | static_cast<u8>(NintendoTagId::EncryptedData1), | ||
| 893 | "Unexpected tag id"); | ||
| 894 | |||
| 895 | std::vector<u8> beacon_data(data0_size + data1_size); | ||
| 896 | Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size); | ||
| 897 | Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size); | ||
| 898 | |||
| 899 | // Decrypt the data | ||
| 900 | DecryptBeaconData(net_info, beacon_data); | ||
| 901 | |||
| 902 | // The beacon data header contains the MD5 hash of the data. | ||
| 903 | BeaconData beacon_header; | ||
| 904 | std::memcpy(&beacon_header, beacon_data.data(), sizeof(beacon_header)); | ||
| 905 | |||
| 906 | // TODO(Subv): Verify the MD5 hash of the data and return 0xE1211005 if invalid. | ||
| 907 | |||
| 908 | u8 num_nodes = net_info.max_nodes; | ||
| 909 | |||
| 910 | std::vector<NodeInfo> nodes; | ||
| 911 | |||
| 912 | for (int i = 0; i < num_nodes; ++i) { | ||
| 913 | BeaconNodeInfo info; | ||
| 914 | std::memcpy(&info, beacon_data.data() + sizeof(beacon_header) + i * sizeof(info), | ||
| 915 | sizeof(info)); | ||
| 916 | |||
| 917 | // Deserialize the node information. | ||
| 918 | NodeInfo node{}; | ||
| 919 | node.friend_code_seed = info.friend_code_seed; | ||
| 920 | node.network_node_id = info.network_node_id; | ||
| 921 | for (int i = 0; i < info.username.size(); ++i) | ||
| 922 | node.username[i] = info.username[i]; | ||
| 923 | |||
| 924 | nodes.push_back(node); | ||
| 925 | } | ||
| 926 | |||
| 927 | Memory::ZeroBlock(output_buffer_addr, sizeof(NodeInfo) * UDSMaxNodes); | ||
| 928 | Memory::WriteBlock(output_buffer_addr, nodes.data(), sizeof(NodeInfo) * nodes.size()); | ||
| 929 | |||
| 930 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 931 | rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0); | ||
| 932 | rb.Push(RESULT_SUCCESS); | ||
| 933 | } | ||
| 934 | |||
| 935 | // Sends a 802.11 beacon frame with information about the current network. | ||
| 936 | static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { | ||
| 937 | // Don't do anything if we're not actually hosting a network | ||
| 938 | if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) | ||
| 939 | return; | ||
| 940 | |||
| 941 | std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info); | ||
| 942 | |||
| 943 | using Network::WifiPacket; | ||
| 944 | WifiPacket packet; | ||
| 945 | packet.type = WifiPacket::PacketType::Beacon; | ||
| 946 | packet.data = std::move(frame); | ||
| 947 | packet.destination_address = Network::BroadcastMac; | ||
| 948 | packet.channel = network_channel; | ||
| 949 | |||
| 950 | SendPacket(packet); | ||
| 951 | |||
| 952 | // Start broadcasting the network, send a beacon frame every 102.4ms. | ||
| 953 | CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late, | ||
| 954 | beacon_broadcast_event, 0); | ||
| 955 | } | ||
| 956 | |||
| 957 | /* | ||
| 958 | * Called when a client connects to an UDS network we're hosting, | ||
| 959 | * updates the connection status and signals the update event. | ||
| 960 | * @param network_node_id Network Node Id of the connecting client. | ||
| 961 | */ | ||
| 962 | void OnClientConnected(u16 network_node_id) { | ||
| 963 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 964 | ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost), | ||
| 965 | "Can not accept clients if we're not hosting a network"); | ||
| 966 | ASSERT_MSG(connection_status.total_nodes < connection_status.max_nodes, | ||
| 967 | "Can not accept connections on a full network"); | ||
| 968 | |||
| 969 | u32 node_id = GetNextAvailableNodeId(); | ||
| 970 | connection_status.node_bitmask |= 1 << node_id; | ||
| 971 | connection_status.changed_nodes |= 1 << node_id; | ||
| 972 | connection_status.nodes[node_id] = network_node_id; | ||
| 973 | connection_status.total_nodes++; | ||
| 974 | connection_status_event->Signal(); | ||
| 975 | } | ||
| 976 | |||
| 977 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 978 | {0x000102C2, nullptr, "Initialize (deprecated)"}, | ||
| 979 | {0x00020000, nullptr, "Scrap"}, | ||
| 980 | {0x00030000, Shutdown, "Shutdown"}, | ||
| 981 | {0x00040402, nullptr, "CreateNetwork (deprecated)"}, | ||
| 982 | {0x00050040, nullptr, "EjectClient"}, | ||
| 983 | {0x00060000, nullptr, "EjectSpectator"}, | ||
| 984 | {0x00070080, nullptr, "UpdateNetworkAttribute"}, | ||
| 985 | {0x00080000, DestroyNetwork, "DestroyNetwork"}, | ||
| 986 | {0x00090442, nullptr, "ConnectNetwork (deprecated)"}, | ||
| 987 | {0x000A0000, nullptr, "DisconnectNetwork"}, | ||
| 988 | {0x000B0000, GetConnectionStatus, "GetConnectionStatus"}, | ||
| 989 | {0x000D0040, nullptr, "GetNodeInformation"}, | ||
| 990 | {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"}, | ||
| 991 | {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, | ||
| 992 | {0x00100042, SetApplicationData, "SetApplicationData"}, | ||
| 993 | {0x00110040, nullptr, "GetApplicationData"}, | ||
| 994 | {0x00120100, Bind, "Bind"}, | ||
| 995 | {0x00130040, nullptr, "Unbind"}, | ||
| 996 | {0x001400C0, nullptr, "PullPacket"}, | ||
| 997 | {0x00150080, nullptr, "SetMaxSendDelay"}, | ||
| 998 | {0x00170182, SendTo, "SendTo"}, | ||
| 999 | {0x001A0000, GetChannel, "GetChannel"}, | ||
| 1000 | {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, | ||
| 1001 | {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"}, | ||
| 1002 | {0x001E0084, nullptr, "ConnectToNetwork"}, | ||
| 1003 | {0x001F0006, DecryptBeaconData, "DecryptBeaconData"}, | ||
| 1004 | {0x00200040, nullptr, "Flush"}, | ||
| 1005 | {0x00210080, nullptr, "SetProbeResponseParam"}, | ||
| 1006 | {0x00220402, nullptr, "ScanOnConnection"}, | ||
| 1007 | }; | ||
| 1008 | |||
| 1009 | NWM_UDS::NWM_UDS() { | ||
| 1010 | connection_status_event = | ||
| 1011 | Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::connection_status_event"); | ||
| 1012 | |||
| 1013 | Register(FunctionTable); | ||
| 1014 | |||
| 1015 | beacon_broadcast_event = | ||
| 1016 | CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | NWM_UDS::~NWM_UDS() { | ||
| 1020 | network_info = {}; | ||
| 1021 | bind_node_events.clear(); | ||
| 1022 | connection_status_event = nullptr; | ||
| 1023 | recv_buffer_memory = nullptr; | ||
| 1024 | |||
| 1025 | { | ||
| 1026 | std::lock_guard<std::mutex> lock(connection_status_mutex); | ||
| 1027 | connection_status = {}; | ||
| 1028 | connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | } // namespace NWM | ||
| 1035 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h deleted file mode 100644 index f1caaf974..000000000 --- a/src/core/hle/service/nwm/nwm_uds.h +++ /dev/null | |||
| @@ -1,111 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <cstddef> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/swap.h" | ||
| 12 | #include "core/hle/service/service.h" | ||
| 13 | |||
| 14 | // Local-WLAN service | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace NWM { | ||
| 18 | |||
| 19 | const size_t ApplicationDataSize = 0xC8; | ||
| 20 | const u8 DefaultNetworkChannel = 11; | ||
| 21 | |||
| 22 | // Number of milliseconds in a TU. | ||
| 23 | const double MillisecondsPerTU = 1.024; | ||
| 24 | // Interval measured in TU, the default value is 100TU = 102.4ms | ||
| 25 | const u16 DefaultBeaconInterval = 100; | ||
| 26 | |||
| 27 | /// The maximum number of nodes that can exist in an UDS session. | ||
| 28 | constexpr u32 UDSMaxNodes = 16; | ||
| 29 | |||
| 30 | struct NodeInfo { | ||
| 31 | u64_le friend_code_seed; | ||
| 32 | std::array<u16_le, 10> username; | ||
| 33 | INSERT_PADDING_BYTES(4); | ||
| 34 | u16_le network_node_id; | ||
| 35 | INSERT_PADDING_BYTES(6); | ||
| 36 | }; | ||
| 37 | |||
| 38 | static_assert(sizeof(NodeInfo) == 40, "NodeInfo has incorrect size."); | ||
| 39 | |||
| 40 | using NodeList = std::vector<NodeInfo>; | ||
| 41 | |||
| 42 | enum class NetworkStatus { | ||
| 43 | NotConnected = 3, | ||
| 44 | ConnectedAsHost = 6, | ||
| 45 | Connecting = 7, | ||
| 46 | ConnectedAsClient = 9, | ||
| 47 | ConnectedAsSpectator = 10, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct ConnectionStatus { | ||
| 51 | u32_le status; | ||
| 52 | INSERT_PADDING_WORDS(1); | ||
| 53 | u16_le network_node_id; | ||
| 54 | u16_le changed_nodes; | ||
| 55 | u16_le nodes[UDSMaxNodes]; | ||
| 56 | u8 total_nodes; | ||
| 57 | u8 max_nodes; | ||
| 58 | u16_le node_bitmask; | ||
| 59 | }; | ||
| 60 | |||
| 61 | static_assert(sizeof(ConnectionStatus) == 0x30, "ConnectionStatus has incorrect size."); | ||
| 62 | |||
| 63 | struct NetworkInfo { | ||
| 64 | std::array<u8, 6> host_mac_address; | ||
| 65 | u8 channel; | ||
| 66 | INSERT_PADDING_BYTES(1); | ||
| 67 | u8 initialized; | ||
| 68 | INSERT_PADDING_BYTES(3); | ||
| 69 | std::array<u8, 3> oui_value; | ||
| 70 | u8 oui_type; | ||
| 71 | // This field is received as BigEndian from the game. | ||
| 72 | u32_be wlan_comm_id; | ||
| 73 | u8 id; | ||
| 74 | INSERT_PADDING_BYTES(1); | ||
| 75 | u16_be attributes; | ||
| 76 | u32_be network_id; | ||
| 77 | u8 total_nodes; | ||
| 78 | u8 max_nodes; | ||
| 79 | INSERT_PADDING_BYTES(2); | ||
| 80 | INSERT_PADDING_BYTES(0x1F); | ||
| 81 | u8 application_data_size; | ||
| 82 | std::array<u8, ApplicationDataSize> application_data; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static_assert(offsetof(NetworkInfo, oui_value) == 0xC, "oui_value is at the wrong offset."); | ||
| 86 | static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset."); | ||
| 87 | static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size."); | ||
| 88 | |||
| 89 | /// Additional block tag ids in the Beacon and Association Response frames | ||
| 90 | enum class TagId : u8 { | ||
| 91 | SSID = 0, | ||
| 92 | SupportedRates = 1, | ||
| 93 | DSParameterSet = 2, | ||
| 94 | TrafficIndicationMap = 5, | ||
| 95 | CountryInformation = 7, | ||
| 96 | ERPInformation = 42, | ||
| 97 | VendorSpecific = 221 | ||
| 98 | }; | ||
| 99 | |||
| 100 | class NWM_UDS final : public Interface { | ||
| 101 | public: | ||
| 102 | NWM_UDS(); | ||
| 103 | ~NWM_UDS() override; | ||
| 104 | |||
| 105 | std::string GetPortName() const override { | ||
| 106 | return "nwm::UDS"; | ||
| 107 | } | ||
| 108 | }; | ||
| 109 | |||
| 110 | } // namespace NWM | ||
| 111 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp deleted file mode 100644 index 73a80d940..000000000 --- a/src/core/hle/service/nwm/uds_beacon.cpp +++ /dev/null | |||
| @@ -1,329 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <cryptopp/aes.h> | ||
| 7 | #include <cryptopp/md5.h> | ||
| 8 | #include <cryptopp/modes.h> | ||
| 9 | #include <cryptopp/sha.h> | ||
| 10 | #include "common/assert.h" | ||
| 11 | #include "core/hle/service/nwm/nwm_uds.h" | ||
| 12 | #include "core/hle/service/nwm/uds_beacon.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace NWM { | ||
| 16 | |||
| 17 | // 802.11 broadcast MAC address | ||
| 18 | constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
| 19 | |||
| 20 | constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds. | ||
| 21 | |||
| 22 | // Note: These values were taken from a packet capture of an o3DS XL | ||
| 23 | // broadcasting a Super Smash Bros. 4 lobby. | ||
| 24 | constexpr u16 DefaultExtraCapabilities = 0x0431; | ||
| 25 | |||
| 26 | // Size of the SSID broadcast by an UDS beacon frame. | ||
| 27 | constexpr u8 UDSBeaconSSIDSize = 8; | ||
| 28 | |||
| 29 | // The maximum size of the data stored in the EncryptedData0 tag (24). | ||
| 30 | constexpr u32 EncryptedDataSizeCutoff = 0xFA; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * NWM Beacon data encryption key, taken from the NWM module code. | ||
| 34 | * We stub this with an all-zeros key as that is enough for Citra's purpose. | ||
| 35 | * The real key can be used here to generate beacons that will be accepted by | ||
| 36 | * a real 3ds. | ||
| 37 | */ | ||
| 38 | constexpr std::array<u8, CryptoPP::AES::BLOCKSIZE> nwm_beacon_key = {}; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Generates a buffer with the fixed parameters of an 802.11 Beacon frame | ||
| 42 | * using dummy values. | ||
| 43 | * @returns A buffer with the fixed parameters of the beacon frame. | ||
| 44 | */ | ||
| 45 | std::vector<u8> GenerateFixedParameters() { | ||
| 46 | std::vector<u8> buffer(sizeof(BeaconFrameHeader)); | ||
| 47 | |||
| 48 | BeaconFrameHeader header{}; | ||
| 49 | // Use a fixed default time for now. | ||
| 50 | // TODO(Subv): Perhaps use the difference between now and the time the network was started? | ||
| 51 | header.timestamp = DefaultNetworkUptime; | ||
| 52 | header.beacon_interval = DefaultBeaconInterval; | ||
| 53 | header.capabilities = DefaultExtraCapabilities; | ||
| 54 | |||
| 55 | std::memcpy(buffer.data(), &header, sizeof(header)); | ||
| 56 | |||
| 57 | return buffer; | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte all-zero SSID value. | ||
| 62 | * @returns A buffer with the SSID tag. | ||
| 63 | */ | ||
| 64 | std::vector<u8> GenerateSSIDTag() { | ||
| 65 | std::vector<u8> buffer(sizeof(TagHeader) + UDSBeaconSSIDSize); | ||
| 66 | |||
| 67 | TagHeader tag_header{}; | ||
| 68 | tag_header.tag_id = static_cast<u8>(TagId::SSID); | ||
| 69 | tag_header.length = UDSBeaconSSIDSize; | ||
| 70 | |||
| 71 | std::memcpy(buffer.data(), &tag_header, sizeof(TagHeader)); | ||
| 72 | |||
| 73 | // The rest of the buffer is already filled with zeros. | ||
| 74 | |||
| 75 | return buffer; | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Generates a buffer with the basic tagged parameters of an 802.11 Beacon frame | ||
| 80 | * such as SSID, Rate Information, Country Information, etc. | ||
| 81 | * @returns A buffer with the tagged parameters of the beacon frame. | ||
| 82 | */ | ||
| 83 | std::vector<u8> GenerateBasicTaggedParameters() { | ||
| 84 | // Append the SSID tag | ||
| 85 | std::vector<u8> buffer = GenerateSSIDTag(); | ||
| 86 | |||
| 87 | // TODO(Subv): Add the SupportedRates tag. | ||
| 88 | // TODO(Subv): Add the DSParameterSet tag. | ||
| 89 | // TODO(Subv): Add the TrafficIndicationMap tag. | ||
| 90 | // TODO(Subv): Add the CountryInformation tag. | ||
| 91 | // TODO(Subv): Add the ERPInformation tag. | ||
| 92 | |||
| 93 | return buffer; | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Generates a buffer with the Dummy Nintendo tag. | ||
| 98 | * It is currently unknown what this tag does. | ||
| 99 | * TODO(Subv): Figure out if this is needed and what it does. | ||
| 100 | * @returns A buffer with the Nintendo tagged parameters of the beacon frame. | ||
| 101 | */ | ||
| 102 | std::vector<u8> GenerateNintendoDummyTag() { | ||
| 103 | // Note: These values were taken from a packet capture of an o3DS XL | ||
| 104 | // broadcasting a Super Smash Bros. 4 lobby. | ||
| 105 | constexpr std::array<u8, 3> dummy_data = {0x0A, 0x00, 0x00}; | ||
| 106 | |||
| 107 | DummyTag tag{}; | ||
| 108 | tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); | ||
| 109 | tag.header.length = sizeof(DummyTag) - sizeof(TagHeader); | ||
| 110 | tag.oui_type = static_cast<u8>(NintendoTagId::Dummy); | ||
| 111 | tag.oui = NintendoOUI; | ||
| 112 | tag.data = dummy_data; | ||
| 113 | |||
| 114 | std::vector<u8> buffer(sizeof(DummyTag)); | ||
| 115 | std::memcpy(buffer.data(), &tag, sizeof(DummyTag)); | ||
| 116 | |||
| 117 | return buffer; | ||
| 118 | } | ||
| 119 | |||
| 120 | /** | ||
| 121 | * Generates a buffer with the Network Info Nintendo tag. | ||
| 122 | * This tag contains the network information of the network that is being broadcast. | ||
| 123 | * It also contains the application data provided by the application that opened the network. | ||
| 124 | * @returns A buffer with the Nintendo network info parameter of the beacon frame. | ||
| 125 | */ | ||
| 126 | std::vector<u8> GenerateNintendoNetworkInfoTag(const NetworkInfo& network_info) { | ||
| 127 | NetworkInfoTag tag{}; | ||
| 128 | tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); | ||
| 129 | tag.header.length = | ||
| 130 | sizeof(NetworkInfoTag) - sizeof(TagHeader) + network_info.application_data_size; | ||
| 131 | tag.appdata_size = network_info.application_data_size; | ||
| 132 | // Set the hash to zero initially, it will be updated once we calculate it. | ||
| 133 | tag.sha_hash = {}; | ||
| 134 | |||
| 135 | // Ensure the network structure has the correct OUI and OUI type. | ||
| 136 | ASSERT(network_info.oui_type == static_cast<u8>(NintendoTagId::NetworkInfo)); | ||
| 137 | ASSERT(network_info.oui_value == NintendoOUI); | ||
| 138 | |||
| 139 | // Ensure the application data size is less than the maximum value. | ||
| 140 | ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, "Data size is too big."); | ||
| 141 | |||
| 142 | // This tag contains the network info structure starting at the OUI. | ||
| 143 | std::memcpy(tag.network_info.data(), &network_info.oui_value, tag.network_info.size()); | ||
| 144 | |||
| 145 | // Copy the tag and the data so we can calculate the SHA1 over it. | ||
| 146 | std::vector<u8> buffer(sizeof(tag) + network_info.application_data_size); | ||
| 147 | std::memcpy(buffer.data(), &tag, sizeof(tag)); | ||
| 148 | std::memcpy(buffer.data() + sizeof(tag), network_info.application_data.data(), | ||
| 149 | network_info.application_data_size); | ||
| 150 | |||
| 151 | // Calculate the SHA1 of the contents of the tag. | ||
| 152 | std::array<u8, CryptoPP::SHA1::DIGESTSIZE> hash; | ||
| 153 | CryptoPP::SHA1().CalculateDigest(hash.data(), | ||
| 154 | buffer.data() + offsetof(NetworkInfoTag, network_info), | ||
| 155 | buffer.size() - sizeof(TagHeader)); | ||
| 156 | |||
| 157 | // Copy it directly into the buffer, overwriting the zeros that we had previously placed there. | ||
| 158 | std::memcpy(buffer.data() + offsetof(NetworkInfoTag, sha_hash), hash.data(), hash.size()); | ||
| 159 | |||
| 160 | return buffer; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* | ||
| 164 | * Calculates the CTR used for the AES-CTR encryption of the data stored in the | ||
| 165 | * EncryptedDataTags. | ||
| 166 | * @returns The CTR used for beacon crypto. | ||
| 167 | */ | ||
| 168 | std::array<u8, CryptoPP::AES::BLOCKSIZE> GetBeaconCryptoCTR(const NetworkInfo& network_info) { | ||
| 169 | BeaconDataCryptoCTR data{}; | ||
| 170 | |||
| 171 | data.host_mac = network_info.host_mac_address; | ||
| 172 | data.wlan_comm_id = network_info.wlan_comm_id; | ||
| 173 | data.id = network_info.id; | ||
| 174 | data.network_id = network_info.network_id; | ||
| 175 | |||
| 176 | std::array<u8, CryptoPP::AES::BLOCKSIZE> hash; | ||
| 177 | std::memcpy(hash.data(), &data, sizeof(data)); | ||
| 178 | |||
| 179 | return hash; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Serializes the node information into the format needed for network transfer, | ||
| 184 | * and then encrypts it with the NWM key. | ||
| 185 | * @returns The serialized and encrypted node information. | ||
| 186 | */ | ||
| 187 | std::vector<u8> GeneratedEncryptedData(const NetworkInfo& network_info, const NodeList& nodes) { | ||
| 188 | std::vector<u8> buffer(sizeof(BeaconData)); | ||
| 189 | |||
| 190 | BeaconData data{}; | ||
| 191 | std::memcpy(buffer.data(), &data, sizeof(BeaconData)); | ||
| 192 | |||
| 193 | for (const NodeInfo& node : nodes) { | ||
| 194 | // Serialize each node and convert the data from | ||
| 195 | // host byte-order to Big Endian. | ||
| 196 | BeaconNodeInfo info{}; | ||
| 197 | info.friend_code_seed = node.friend_code_seed; | ||
| 198 | info.network_node_id = node.network_node_id; | ||
| 199 | for (int i = 0; i < info.username.size(); ++i) | ||
| 200 | info.username[i] = node.username[i]; | ||
| 201 | |||
| 202 | buffer.insert(buffer.end(), reinterpret_cast<u8*>(&info), | ||
| 203 | reinterpret_cast<u8*>(&info) + sizeof(info)); | ||
| 204 | } | ||
| 205 | |||
| 206 | // Calculate the MD5 hash of the data in the buffer, not including the hash field. | ||
| 207 | std::array<u8, CryptoPP::MD5::DIGESTSIZE> hash; | ||
| 208 | CryptoPP::MD5().CalculateDigest(hash.data(), buffer.data() + offsetof(BeaconData, bitmask), | ||
| 209 | buffer.size() - sizeof(data.md5_hash)); | ||
| 210 | |||
| 211 | // Copy the hash into the buffer. | ||
| 212 | std::memcpy(buffer.data(), hash.data(), hash.size()); | ||
| 213 | |||
| 214 | // Encrypt the data using AES-CTR and the NWM beacon key. | ||
| 215 | using CryptoPP::AES; | ||
| 216 | std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); | ||
| 217 | CryptoPP::CTR_Mode<AES>::Encryption aes; | ||
| 218 | aes.SetKeyWithIV(nwm_beacon_key.data(), AES::BLOCKSIZE, counter.data()); | ||
| 219 | aes.ProcessData(buffer.data(), buffer.data(), buffer.size()); | ||
| 220 | |||
| 221 | return buffer; | ||
| 222 | } | ||
| 223 | |||
| 224 | void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer) { | ||
| 225 | // Decrypt the data using AES-CTR and the NWM beacon key. | ||
| 226 | using CryptoPP::AES; | ||
| 227 | std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); | ||
| 228 | CryptoPP::CTR_Mode<AES>::Decryption aes; | ||
| 229 | aes.SetKeyWithIV(nwm_beacon_key.data(), AES::BLOCKSIZE, counter.data()); | ||
| 230 | aes.ProcessData(buffer.data(), buffer.data(), buffer.size()); | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * Generates a buffer with the Network Info Nintendo tag. | ||
| 235 | * This tag contains the first portion of the encrypted payload in the 802.11 beacon frame. | ||
| 236 | * The encrypted payload contains information about the nodes currently connected to the network. | ||
| 237 | * @returns A buffer with the first Nintendo encrypted data parameters of the beacon frame. | ||
| 238 | */ | ||
| 239 | std::vector<u8> GenerateNintendoFirstEncryptedDataTag(const NetworkInfo& network_info, | ||
| 240 | const NodeList& nodes) { | ||
| 241 | const size_t payload_size = | ||
| 242 | std::min<size_t>(EncryptedDataSizeCutoff, nodes.size() * sizeof(NodeInfo)); | ||
| 243 | |||
| 244 | EncryptedDataTag tag{}; | ||
| 245 | tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); | ||
| 246 | tag.header.length = static_cast<u8>(sizeof(tag) - sizeof(TagHeader) + payload_size); | ||
| 247 | tag.oui_type = static_cast<u8>(NintendoTagId::EncryptedData0); | ||
| 248 | tag.oui = NintendoOUI; | ||
| 249 | |||
| 250 | std::vector<u8> buffer(sizeof(tag) + payload_size); | ||
| 251 | std::memcpy(buffer.data(), &tag, sizeof(tag)); | ||
| 252 | |||
| 253 | std::vector<u8> encrypted_data = GeneratedEncryptedData(network_info, nodes); | ||
| 254 | std::memcpy(buffer.data() + sizeof(tag), encrypted_data.data(), payload_size); | ||
| 255 | |||
| 256 | return buffer; | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * Generates a buffer with the Network Info Nintendo tag. | ||
| 261 | * This tag contains the second portion of the encrypted payload in the 802.11 beacon frame. | ||
| 262 | * The encrypted payload contains information about the nodes currently connected to the network. | ||
| 263 | * This tag is only present if the payload size is greater than EncryptedDataSizeCutoff (0xFA) | ||
| 264 | * bytes. | ||
| 265 | * @returns A buffer with the second Nintendo encrypted data parameters of the beacon frame. | ||
| 266 | */ | ||
| 267 | std::vector<u8> GenerateNintendoSecondEncryptedDataTag(const NetworkInfo& network_info, | ||
| 268 | const NodeList& nodes) { | ||
| 269 | // This tag is only present if the payload is larger than EncryptedDataSizeCutoff (0xFA). | ||
| 270 | if (nodes.size() * sizeof(NodeInfo) <= EncryptedDataSizeCutoff) | ||
| 271 | return {}; | ||
| 272 | |||
| 273 | const size_t payload_size = nodes.size() * sizeof(NodeInfo) - EncryptedDataSizeCutoff; | ||
| 274 | |||
| 275 | const size_t tag_length = sizeof(EncryptedDataTag) - sizeof(TagHeader) + payload_size; | ||
| 276 | |||
| 277 | // TODO(Subv): What does the 3DS do when a game has too much data to fit into the tag? | ||
| 278 | ASSERT_MSG(tag_length <= 255, "Data is too big."); | ||
| 279 | |||
| 280 | EncryptedDataTag tag{}; | ||
| 281 | tag.header.tag_id = static_cast<u8>(TagId::VendorSpecific); | ||
| 282 | tag.header.length = static_cast<u8>(tag_length); | ||
| 283 | tag.oui_type = static_cast<u8>(NintendoTagId::EncryptedData1); | ||
| 284 | tag.oui = NintendoOUI; | ||
| 285 | |||
| 286 | std::vector<u8> buffer(sizeof(tag) + payload_size); | ||
| 287 | std::memcpy(buffer.data(), &tag, sizeof(tag)); | ||
| 288 | |||
| 289 | std::vector<u8> encrypted_data = GeneratedEncryptedData(network_info, nodes); | ||
| 290 | std::memcpy(buffer.data() + sizeof(tag), encrypted_data.data() + EncryptedDataSizeCutoff, | ||
| 291 | payload_size); | ||
| 292 | |||
| 293 | return buffer; | ||
| 294 | } | ||
| 295 | |||
| 296 | /** | ||
| 297 | * Generates a buffer with the Nintendo tagged parameters of an 802.11 Beacon frame | ||
| 298 | * for UDS communication. | ||
| 299 | * @returns A buffer with the Nintendo tagged parameters of the beacon frame. | ||
| 300 | */ | ||
| 301 | std::vector<u8> GenerateNintendoTaggedParameters(const NetworkInfo& network_info, | ||
| 302 | const NodeList& nodes) { | ||
| 303 | ASSERT_MSG(network_info.max_nodes == nodes.size(), "Inconsistent network state."); | ||
| 304 | |||
| 305 | std::vector<u8> buffer = GenerateNintendoDummyTag(); | ||
| 306 | std::vector<u8> network_info_tag = GenerateNintendoNetworkInfoTag(network_info); | ||
| 307 | std::vector<u8> first_data_tag = GenerateNintendoFirstEncryptedDataTag(network_info, nodes); | ||
| 308 | std::vector<u8> second_data_tag = GenerateNintendoSecondEncryptedDataTag(network_info, nodes); | ||
| 309 | |||
| 310 | buffer.insert(buffer.end(), network_info_tag.begin(), network_info_tag.end()); | ||
| 311 | buffer.insert(buffer.end(), first_data_tag.begin(), first_data_tag.end()); | ||
| 312 | buffer.insert(buffer.end(), second_data_tag.begin(), second_data_tag.end()); | ||
| 313 | |||
| 314 | return buffer; | ||
| 315 | } | ||
| 316 | |||
| 317 | std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes) { | ||
| 318 | std::vector<u8> buffer = GenerateFixedParameters(); | ||
| 319 | std::vector<u8> basic_tags = GenerateBasicTaggedParameters(); | ||
| 320 | std::vector<u8> nintendo_tags = GenerateNintendoTaggedParameters(network_info, nodes); | ||
| 321 | |||
| 322 | buffer.insert(buffer.end(), basic_tags.begin(), basic_tags.end()); | ||
| 323 | buffer.insert(buffer.end(), nintendo_tags.begin(), nintendo_tags.end()); | ||
| 324 | |||
| 325 | return buffer; | ||
| 326 | } | ||
| 327 | |||
| 328 | } // namespace NWM | ||
| 329 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_beacon.h b/src/core/hle/service/nwm/uds_beacon.h deleted file mode 100644 index 50cc76da2..000000000 --- a/src/core/hle/service/nwm/uds_beacon.h +++ /dev/null | |||
| @@ -1,140 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <deque> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/swap.h" | ||
| 12 | #include "core/hle/service/service.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace NWM { | ||
| 16 | |||
| 17 | using MacAddress = std::array<u8, 6>; | ||
| 18 | constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Internal vendor-specific tag ids as stored inside | ||
| 22 | * VendorSpecific blocks in the Beacon frames. | ||
| 23 | */ | ||
| 24 | enum class NintendoTagId : u8 { | ||
| 25 | Dummy = 20, | ||
| 26 | NetworkInfo = 21, | ||
| 27 | EncryptedData0 = 24, | ||
| 28 | EncryptedData1 = 25, | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct BeaconEntryHeader { | ||
| 32 | u32_le total_size; | ||
| 33 | INSERT_PADDING_BYTES(1); | ||
| 34 | u8 wifi_channel; | ||
| 35 | INSERT_PADDING_BYTES(2); | ||
| 36 | MacAddress mac_address; | ||
| 37 | INSERT_PADDING_BYTES(6); | ||
| 38 | u32_le unk_size; | ||
| 39 | u32_le header_size; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static_assert(sizeof(BeaconEntryHeader) == 0x1C, "BeaconEntryHeader has incorrect size."); | ||
| 43 | |||
| 44 | struct BeaconDataReplyHeader { | ||
| 45 | u32_le max_output_size; | ||
| 46 | u32_le total_size; | ||
| 47 | u32_le total_entries; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static_assert(sizeof(BeaconDataReplyHeader) == 12, "BeaconDataReplyHeader has incorrect size."); | ||
| 51 | |||
| 52 | #pragma pack(push, 1) | ||
| 53 | struct BeaconFrameHeader { | ||
| 54 | // Number of microseconds the AP has been active. | ||
| 55 | u64_le timestamp; | ||
| 56 | // Interval between beacon transmissions, expressed in TU. | ||
| 57 | u16_le beacon_interval; | ||
| 58 | // Indicates the presence of optional capabilities. | ||
| 59 | u16_le capabilities; | ||
| 60 | }; | ||
| 61 | #pragma pack(pop) | ||
| 62 | |||
| 63 | static_assert(sizeof(BeaconFrameHeader) == 12, "BeaconFrameHeader has incorrect size."); | ||
| 64 | |||
| 65 | struct TagHeader { | ||
| 66 | u8 tag_id; | ||
| 67 | u8 length; | ||
| 68 | }; | ||
| 69 | |||
| 70 | static_assert(sizeof(TagHeader) == 2, "TagHeader has incorrect size."); | ||
| 71 | |||
| 72 | struct DummyTag { | ||
| 73 | TagHeader header; | ||
| 74 | std::array<u8, 3> oui; | ||
| 75 | u8 oui_type; | ||
| 76 | std::array<u8, 3> data; | ||
| 77 | }; | ||
| 78 | |||
| 79 | static_assert(sizeof(DummyTag) == 9, "DummyTag has incorrect size."); | ||
| 80 | |||
| 81 | struct NetworkInfoTag { | ||
| 82 | TagHeader header; | ||
| 83 | std::array<u8, 0x1F> network_info; | ||
| 84 | std::array<u8, 0x14> sha_hash; | ||
| 85 | u8 appdata_size; | ||
| 86 | }; | ||
| 87 | |||
| 88 | static_assert(sizeof(NetworkInfoTag) == 54, "NetworkInfoTag has incorrect size."); | ||
| 89 | |||
| 90 | struct EncryptedDataTag { | ||
| 91 | TagHeader header; | ||
| 92 | std::array<u8, 3> oui; | ||
| 93 | u8 oui_type; | ||
| 94 | }; | ||
| 95 | |||
| 96 | static_assert(sizeof(EncryptedDataTag) == 6, "EncryptedDataTag has incorrect size."); | ||
| 97 | |||
| 98 | #pragma pack(push, 1) | ||
| 99 | // The raw bytes of this structure are the CTR used in the encryption (AES-CTR) | ||
| 100 | // of the beacon data stored in the EncryptedDataTags. | ||
| 101 | struct BeaconDataCryptoCTR { | ||
| 102 | MacAddress host_mac; | ||
| 103 | u32_le wlan_comm_id; | ||
| 104 | u8 id; | ||
| 105 | INSERT_PADDING_BYTES(1); | ||
| 106 | u32_le network_id; | ||
| 107 | }; | ||
| 108 | |||
| 109 | static_assert(sizeof(BeaconDataCryptoCTR) == 0x10, "BeaconDataCryptoCTR has incorrect size."); | ||
| 110 | |||
| 111 | struct BeaconNodeInfo { | ||
| 112 | u64_be friend_code_seed; | ||
| 113 | std::array<u16_be, 10> username; | ||
| 114 | u16_be network_node_id; | ||
| 115 | }; | ||
| 116 | |||
| 117 | static_assert(sizeof(BeaconNodeInfo) == 0x1E, "BeaconNodeInfo has incorrect size."); | ||
| 118 | |||
| 119 | struct BeaconData { | ||
| 120 | std::array<u8, 0x10> md5_hash; | ||
| 121 | u16_be bitmask; | ||
| 122 | }; | ||
| 123 | #pragma pack(pop) | ||
| 124 | |||
| 125 | static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Decrypts the beacon data buffer for the network described by `network_info`. | ||
| 129 | */ | ||
| 130 | void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Generates an 802.11 beacon frame starting at the management frame header. | ||
| 134 | * This frame contains information about the network and its connected clients. | ||
| 135 | * @returns The generated frame. | ||
| 136 | */ | ||
| 137 | std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes); | ||
| 138 | |||
| 139 | } // namespace NWM | ||
| 140 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_connection.cpp b/src/core/hle/service/nwm/uds_connection.cpp deleted file mode 100644 index c74f51253..000000000 --- a/src/core/hle/service/nwm/uds_connection.cpp +++ /dev/null | |||
| @@ -1,88 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/nwm/nwm_uds.h" | ||
| 6 | #include "core/hle/service/nwm/uds_connection.h" | ||
| 7 | #include "fmt/format.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | // Note: These values were taken from a packet capture of an o3DS XL | ||
| 13 | // broadcasting a Super Smash Bros. 4 lobby. | ||
| 14 | constexpr u16 DefaultExtraCapabilities = 0x0431; | ||
| 15 | |||
| 16 | std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq) { | ||
| 17 | AuthenticationFrame frame{}; | ||
| 18 | frame.auth_seq = static_cast<u16>(seq); | ||
| 19 | |||
| 20 | std::vector<u8> data(sizeof(frame)); | ||
| 21 | std::memcpy(data.data(), &frame, sizeof(frame)); | ||
| 22 | |||
| 23 | return data; | ||
| 24 | } | ||
| 25 | |||
| 26 | AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body) { | ||
| 27 | AuthenticationFrame frame; | ||
| 28 | std::memcpy(&frame, body.data(), sizeof(frame)); | ||
| 29 | |||
| 30 | return static_cast<AuthenticationSeq>(frame.auth_seq); | ||
| 31 | } | ||
| 32 | |||
| 33 | /** | ||
| 34 | * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte character representation of the | ||
| 35 | * specified network id as the SSID value. | ||
| 36 | * @param network_id The network id to use. | ||
| 37 | * @returns A buffer with the SSID tag. | ||
| 38 | */ | ||
| 39 | static std::vector<u8> GenerateSSIDTag(u32 network_id) { | ||
| 40 | constexpr u8 SSIDSize = 8; | ||
| 41 | |||
| 42 | struct { | ||
| 43 | u8 id = static_cast<u8>(TagId::SSID); | ||
| 44 | u8 size = SSIDSize; | ||
| 45 | } tag_header; | ||
| 46 | |||
| 47 | std::vector<u8> buffer(sizeof(tag_header) + SSIDSize); | ||
| 48 | |||
| 49 | std::memcpy(buffer.data(), &tag_header, sizeof(tag_header)); | ||
| 50 | |||
| 51 | std::string network_name = fmt::format("{0:08X}", network_id); | ||
| 52 | |||
| 53 | std::memcpy(buffer.data() + sizeof(tag_header), network_name.c_str(), SSIDSize); | ||
| 54 | |||
| 55 | return buffer; | ||
| 56 | } | ||
| 57 | |||
| 58 | std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id) { | ||
| 59 | AssociationResponseFrame frame{}; | ||
| 60 | frame.capabilities = DefaultExtraCapabilities; | ||
| 61 | frame.status_code = static_cast<u16>(status); | ||
| 62 | // The association id is ORed with this magic value (0xC000) | ||
| 63 | constexpr u16 AssociationIdMagic = 0xC000; | ||
| 64 | frame.assoc_id = association_id | AssociationIdMagic; | ||
| 65 | |||
| 66 | std::vector<u8> data(sizeof(frame)); | ||
| 67 | std::memcpy(data.data(), &frame, sizeof(frame)); | ||
| 68 | |||
| 69 | auto ssid_tag = GenerateSSIDTag(network_id); | ||
| 70 | data.insert(data.end(), ssid_tag.begin(), ssid_tag.end()); | ||
| 71 | |||
| 72 | // TODO(Subv): Add the SupportedRates tag. | ||
| 73 | // TODO(Subv): Add the DSParameterSet tag. | ||
| 74 | // TODO(Subv): Add the ERPInformation tag. | ||
| 75 | return data; | ||
| 76 | } | ||
| 77 | |||
| 78 | std::tuple<AssocStatus, u16> GetAssociationResult(const std::vector<u8>& body) { | ||
| 79 | AssociationResponseFrame frame; | ||
| 80 | memcpy(&frame, body.data(), sizeof(frame)); | ||
| 81 | |||
| 82 | constexpr u16 AssociationIdMask = 0x3FFF; | ||
| 83 | return std::make_tuple(static_cast<AssocStatus>(frame.status_code), | ||
| 84 | frame.assoc_id & AssociationIdMask); | ||
| 85 | } | ||
| 86 | |||
| 87 | } // namespace NWM | ||
| 88 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_connection.h b/src/core/hle/service/nwm/uds_connection.h deleted file mode 100644 index a664f8471..000000000 --- a/src/core/hle/service/nwm/uds_connection.h +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <tuple> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace NWM { | ||
| 15 | |||
| 16 | /// Sequence number of the 802.11 authentication frames. | ||
| 17 | enum class AuthenticationSeq : u16 { SEQ1 = 1, SEQ2 = 2 }; | ||
| 18 | |||
| 19 | enum class AuthAlgorithm : u16 { OpenSystem = 0 }; | ||
| 20 | |||
| 21 | enum class AuthStatus : u16 { Successful = 0 }; | ||
| 22 | |||
| 23 | enum class AssocStatus : u16 { Successful = 0 }; | ||
| 24 | |||
| 25 | struct AuthenticationFrame { | ||
| 26 | u16_le auth_algorithm = static_cast<u16>(AuthAlgorithm::OpenSystem); | ||
| 27 | u16_le auth_seq; | ||
| 28 | u16_le status_code = static_cast<u16>(AuthStatus::Successful); | ||
| 29 | }; | ||
| 30 | |||
| 31 | static_assert(sizeof(AuthenticationFrame) == 6, "AuthenticationFrame has wrong size"); | ||
| 32 | |||
| 33 | struct AssociationResponseFrame { | ||
| 34 | u16_le capabilities; | ||
| 35 | u16_le status_code; | ||
| 36 | u16_le assoc_id; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame has wrong size"); | ||
| 40 | |||
| 41 | /// Generates an 802.11 authentication frame, starting at the frame body. | ||
| 42 | std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq); | ||
| 43 | |||
| 44 | /// Returns the sequence number from the body of an Authentication frame. | ||
| 45 | AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body); | ||
| 46 | |||
| 47 | /// Generates an 802.11 association response frame with the specified status, association id and | ||
| 48 | /// network id, starting at the frame body. | ||
| 49 | std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id); | ||
| 50 | |||
| 51 | /// Returns a tuple of (association status, association id) from the body of an AssociationResponse | ||
| 52 | /// frame. | ||
| 53 | std::tuple<AssocStatus, u16> GetAssociationResult(const std::vector<u8>& body); | ||
| 54 | |||
| 55 | } // namespace NWM | ||
| 56 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_data.cpp b/src/core/hle/service/nwm/uds_data.cpp deleted file mode 100644 index 4b389710f..000000000 --- a/src/core/hle/service/nwm/uds_data.cpp +++ /dev/null | |||
| @@ -1,373 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstring> | ||
| 7 | #include <cryptopp/aes.h> | ||
| 8 | #include <cryptopp/ccm.h> | ||
| 9 | #include <cryptopp/filters.h> | ||
| 10 | #include <cryptopp/md5.h> | ||
| 11 | #include <cryptopp/modes.h> | ||
| 12 | #include "core/hle/service/nwm/nwm_uds.h" | ||
| 13 | #include "core/hle/service/nwm/uds_data.h" | ||
| 14 | #include "core/hw/aes/key.h" | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace NWM { | ||
| 18 | |||
| 19 | using MacAddress = std::array<u8, 6>; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Generates a SNAP-enabled 802.2 LLC header for the specified protocol. | ||
| 23 | * @returns a buffer with the bytes of the generated header. | ||
| 24 | */ | ||
| 25 | static std::vector<u8> GenerateLLCHeader(EtherType protocol) { | ||
| 26 | LLCHeader header{}; | ||
| 27 | header.protocol = static_cast<u16>(protocol); | ||
| 28 | |||
| 29 | std::vector<u8> buffer(sizeof(header)); | ||
| 30 | memcpy(buffer.data(), &header, sizeof(header)); | ||
| 31 | |||
| 32 | return buffer; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Generates a Nintendo UDS SecureData header with the specified parameters. | ||
| 37 | * @returns a buffer with the bytes of the generated header. | ||
| 38 | */ | ||
| 39 | static std::vector<u8> GenerateSecureDataHeader(u16 data_size, u8 channel, u16 dest_node_id, | ||
| 40 | u16 src_node_id, u16 sequence_number) { | ||
| 41 | SecureDataHeader header{}; | ||
| 42 | header.protocol_size = data_size + sizeof(SecureDataHeader); | ||
| 43 | // Note: This size includes everything except the first 4 bytes of the structure, | ||
| 44 | // reinforcing the hypotheses that the first 4 bytes are actually the header of | ||
| 45 | // another container protocol. | ||
| 46 | header.securedata_size = data_size + sizeof(SecureDataHeader) - 4; | ||
| 47 | // Frames sent by the emulated application are never UDS management frames | ||
| 48 | header.is_management = 0; | ||
| 49 | header.data_channel = channel; | ||
| 50 | header.sequence_number = sequence_number; | ||
| 51 | header.dest_node_id = dest_node_id; | ||
| 52 | header.src_node_id = src_node_id; | ||
| 53 | |||
| 54 | std::vector<u8> buffer(sizeof(header)); | ||
| 55 | memcpy(buffer.data(), &header, sizeof(header)); | ||
| 56 | |||
| 57 | return buffer; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Calculates the CTR used for the AES-CTR process that calculates | ||
| 62 | * the CCMP crypto key for data frames. | ||
| 63 | * @returns The CTR used for data frames crypto key generation. | ||
| 64 | */ | ||
| 65 | static std::array<u8, CryptoPP::MD5::DIGESTSIZE> GetDataCryptoCTR(const NetworkInfo& network_info) { | ||
| 66 | DataFrameCryptoCTR data{}; | ||
| 67 | |||
| 68 | data.host_mac = network_info.host_mac_address; | ||
| 69 | data.wlan_comm_id = network_info.wlan_comm_id; | ||
| 70 | data.id = network_info.id; | ||
| 71 | data.network_id = network_info.network_id; | ||
| 72 | |||
| 73 | std::array<u8, CryptoPP::MD5::DIGESTSIZE> hash; | ||
| 74 | CryptoPP::MD5().CalculateDigest(hash.data(), reinterpret_cast<u8*>(&data), sizeof(data)); | ||
| 75 | |||
| 76 | return hash; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Generates the key used for encrypting the 802.11 data frames generated by UDS. | ||
| 81 | * @returns The key used for data frames crypto. | ||
| 82 | */ | ||
| 83 | static std::array<u8, CryptoPP::AES::BLOCKSIZE> GenerateDataCCMPKey( | ||
| 84 | const std::vector<u8>& passphrase, const NetworkInfo& network_info) { | ||
| 85 | // Calculate the MD5 hash of the input passphrase. | ||
| 86 | std::array<u8, CryptoPP::MD5::DIGESTSIZE> passphrase_hash; | ||
| 87 | CryptoPP::MD5().CalculateDigest(passphrase_hash.data(), passphrase.data(), passphrase.size()); | ||
| 88 | |||
| 89 | std::array<u8, CryptoPP::AES::BLOCKSIZE> ccmp_key; | ||
| 90 | |||
| 91 | // The CCMP key is the result of encrypting the MD5 hash of the passphrase with AES-CTR using | ||
| 92 | // keyslot 0x2D. | ||
| 93 | using CryptoPP::AES; | ||
| 94 | std::array<u8, CryptoPP::MD5::DIGESTSIZE> counter = GetDataCryptoCTR(network_info); | ||
| 95 | std::array<u8, AES::BLOCKSIZE> key = HW::AES::GetNormalKey(HW::AES::KeySlotID::UDSDataKey); | ||
| 96 | CryptoPP::CTR_Mode<AES>::Encryption aes; | ||
| 97 | aes.SetKeyWithIV(key.data(), AES::BLOCKSIZE, counter.data()); | ||
| 98 | aes.ProcessData(ccmp_key.data(), passphrase_hash.data(), passphrase_hash.size()); | ||
| 99 | |||
| 100 | return ccmp_key; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Generates the Additional Authenticated Data (AAD) for an UDS 802.11 encrypted data frame. | ||
| 105 | * @returns a buffer with the bytes of the AAD. | ||
| 106 | */ | ||
| 107 | static std::vector<u8> GenerateCCMPAAD(const MacAddress& sender, const MacAddress& receiver, | ||
| 108 | const MacAddress& bssid, u16 frame_control) { | ||
| 109 | // Reference: IEEE 802.11-2007 | ||
| 110 | |||
| 111 | // 8.3.3.3.2 Construct AAD (22-30 bytes) | ||
| 112 | // The AAD is constructed from the MPDU header. The AAD does not include the header Duration | ||
| 113 | // field, because the Duration field value can change due to normal IEEE 802.11 operation (e.g., | ||
| 114 | // a rate change during retransmission). For similar reasons, several subfields in the Frame | ||
| 115 | // Control field are masked to 0. | ||
| 116 | struct { | ||
| 117 | u16_be FC; // MPDU Frame Control field | ||
| 118 | MacAddress A1; | ||
| 119 | MacAddress A2; | ||
| 120 | MacAddress A3; | ||
| 121 | u16_be SC; // MPDU Sequence Control field | ||
| 122 | } aad_struct{}; | ||
| 123 | |||
| 124 | constexpr u16 AADFrameControlMask = 0x8FC7; | ||
| 125 | aad_struct.FC = frame_control & AADFrameControlMask; | ||
| 126 | aad_struct.SC = 0; | ||
| 127 | |||
| 128 | bool to_ds = (frame_control & (1 << 0)) != 0; | ||
| 129 | bool from_ds = (frame_control & (1 << 1)) != 0; | ||
| 130 | // In the 802.11 standard, ToDS = 1 and FromDS = 1 is a valid configuration, | ||
| 131 | // however, the 3DS doesn't seem to transmit frames with such combination. | ||
| 132 | ASSERT_MSG(to_ds != from_ds, "Invalid combination"); | ||
| 133 | |||
| 134 | // The meaning of the address fields depends on the ToDS and FromDS fields. | ||
| 135 | if (from_ds) { | ||
| 136 | aad_struct.A1 = receiver; | ||
| 137 | aad_struct.A2 = bssid; | ||
| 138 | aad_struct.A3 = sender; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (to_ds) { | ||
| 142 | aad_struct.A1 = bssid; | ||
| 143 | aad_struct.A2 = sender; | ||
| 144 | aad_struct.A3 = receiver; | ||
| 145 | } | ||
| 146 | |||
| 147 | std::vector<u8> aad(sizeof(aad_struct)); | ||
| 148 | std::memcpy(aad.data(), &aad_struct, sizeof(aad_struct)); | ||
| 149 | |||
| 150 | return aad; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Decrypts the payload of an encrypted 802.11 data frame using the specified key. | ||
| 155 | * @returns The decrypted payload. | ||
| 156 | */ | ||
| 157 | static std::vector<u8> DecryptDataFrame(const std::vector<u8>& encrypted_payload, | ||
| 158 | const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key, | ||
| 159 | const MacAddress& sender, const MacAddress& receiver, | ||
| 160 | const MacAddress& bssid, u16 sequence_number, | ||
| 161 | u16 frame_control) { | ||
| 162 | |||
| 163 | // Reference: IEEE 802.11-2007 | ||
| 164 | |||
| 165 | std::vector<u8> aad = GenerateCCMPAAD(sender, receiver, bssid, frame_control); | ||
| 166 | |||
| 167 | std::vector<u8> packet_number{0, | ||
| 168 | 0, | ||
| 169 | 0, | ||
| 170 | 0, | ||
| 171 | static_cast<u8>((sequence_number >> 8) & 0xFF), | ||
| 172 | static_cast<u8>(sequence_number & 0xFF)}; | ||
| 173 | |||
| 174 | // 8.3.3.3.3 Construct CCM nonce (13 bytes) | ||
| 175 | std::vector<u8> nonce; | ||
| 176 | nonce.push_back(0); // priority | ||
| 177 | nonce.insert(nonce.end(), sender.begin(), sender.end()); // Address 2 | ||
| 178 | nonce.insert(nonce.end(), packet_number.begin(), packet_number.end()); // PN | ||
| 179 | |||
| 180 | try { | ||
| 181 | CryptoPP::CCM<CryptoPP::AES, 8>::Decryption d; | ||
| 182 | d.SetKeyWithIV(ccmp_key.data(), ccmp_key.size(), nonce.data(), nonce.size()); | ||
| 183 | d.SpecifyDataLengths(aad.size(), encrypted_payload.size() - 8, 0); | ||
| 184 | |||
| 185 | CryptoPP::AuthenticatedDecryptionFilter df( | ||
| 186 | d, nullptr, CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_END | | ||
| 187 | CryptoPP::AuthenticatedDecryptionFilter::THROW_EXCEPTION); | ||
| 188 | // put aad | ||
| 189 | df.ChannelPut(CryptoPP::AAD_CHANNEL, aad.data(), aad.size()); | ||
| 190 | |||
| 191 | // put cipher with mac | ||
| 192 | df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, encrypted_payload.data(), | ||
| 193 | encrypted_payload.size() - 8); | ||
| 194 | df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, | ||
| 195 | encrypted_payload.data() + encrypted_payload.size() - 8, 8); | ||
| 196 | |||
| 197 | df.ChannelMessageEnd(CryptoPP::AAD_CHANNEL); | ||
| 198 | df.ChannelMessageEnd(CryptoPP::DEFAULT_CHANNEL); | ||
| 199 | df.SetRetrievalChannel(CryptoPP::DEFAULT_CHANNEL); | ||
| 200 | |||
| 201 | size_t size = df.MaxRetrievable(); | ||
| 202 | |||
| 203 | std::vector<u8> pdata(size); | ||
| 204 | df.Get(pdata.data(), size); | ||
| 205 | return pdata; | ||
| 206 | } catch (CryptoPP::Exception&) { | ||
| 207 | LOG_ERROR(Service_NWM, "failed to decrypt"); | ||
| 208 | } | ||
| 209 | |||
| 210 | return {}; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* | ||
| 214 | * Encrypts the payload of an 802.11 data frame using the specified key. | ||
| 215 | * @returns The encrypted payload. | ||
| 216 | */ | ||
| 217 | static std::vector<u8> EncryptDataFrame(const std::vector<u8>& payload, | ||
| 218 | const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key, | ||
| 219 | const MacAddress& sender, const MacAddress& receiver, | ||
| 220 | const MacAddress& bssid, u16 sequence_number, | ||
| 221 | u16 frame_control) { | ||
| 222 | // Reference: IEEE 802.11-2007 | ||
| 223 | |||
| 224 | std::vector<u8> aad = GenerateCCMPAAD(sender, receiver, bssid, frame_control); | ||
| 225 | |||
| 226 | std::vector<u8> packet_number{0, | ||
| 227 | 0, | ||
| 228 | 0, | ||
| 229 | 0, | ||
| 230 | static_cast<u8>((sequence_number >> 8) & 0xFF), | ||
| 231 | static_cast<u8>(sequence_number & 0xFF)}; | ||
| 232 | |||
| 233 | // 8.3.3.3.3 Construct CCM nonce (13 bytes) | ||
| 234 | std::vector<u8> nonce; | ||
| 235 | nonce.push_back(0); // priority | ||
| 236 | nonce.insert(nonce.end(), sender.begin(), sender.end()); // Address 2 | ||
| 237 | nonce.insert(nonce.end(), packet_number.begin(), packet_number.end()); // PN | ||
| 238 | |||
| 239 | try { | ||
| 240 | CryptoPP::CCM<CryptoPP::AES, 8>::Encryption d; | ||
| 241 | d.SetKeyWithIV(ccmp_key.data(), ccmp_key.size(), nonce.data(), nonce.size()); | ||
| 242 | d.SpecifyDataLengths(aad.size(), payload.size(), 0); | ||
| 243 | |||
| 244 | CryptoPP::AuthenticatedEncryptionFilter df(d); | ||
| 245 | // put aad | ||
| 246 | df.ChannelPut(CryptoPP::AAD_CHANNEL, aad.data(), aad.size()); | ||
| 247 | df.ChannelMessageEnd(CryptoPP::AAD_CHANNEL); | ||
| 248 | |||
| 249 | // put plaintext | ||
| 250 | df.ChannelPut(CryptoPP::DEFAULT_CHANNEL, payload.data(), payload.size()); | ||
| 251 | df.ChannelMessageEnd(CryptoPP::DEFAULT_CHANNEL); | ||
| 252 | |||
| 253 | df.SetRetrievalChannel(CryptoPP::DEFAULT_CHANNEL); | ||
| 254 | |||
| 255 | size_t size = df.MaxRetrievable(); | ||
| 256 | |||
| 257 | std::vector<u8> cipher(size); | ||
| 258 | df.Get(cipher.data(), size); | ||
| 259 | return cipher; | ||
| 260 | } catch (CryptoPP::Exception&) { | ||
| 261 | LOG_ERROR(Service_NWM, "failed to encrypt"); | ||
| 262 | } | ||
| 263 | |||
| 264 | return {}; | ||
| 265 | } | ||
| 266 | |||
| 267 | std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node, | ||
| 268 | u16 src_node, u16 sequence_number) { | ||
| 269 | std::vector<u8> buffer = GenerateLLCHeader(EtherType::SecureData); | ||
| 270 | std::vector<u8> securedata_header = GenerateSecureDataHeader( | ||
| 271 | static_cast<u16>(data.size()), channel, dest_node, src_node, sequence_number); | ||
| 272 | |||
| 273 | buffer.insert(buffer.end(), securedata_header.begin(), securedata_header.end()); | ||
| 274 | buffer.insert(buffer.end(), data.begin(), data.end()); | ||
| 275 | return buffer; | ||
| 276 | } | ||
| 277 | |||
| 278 | std::vector<u8> GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node_info) { | ||
| 279 | EAPoLStartPacket eapol_start{}; | ||
| 280 | eapol_start.association_id = association_id; | ||
| 281 | eapol_start.node.friend_code_seed = node_info.friend_code_seed; | ||
| 282 | |||
| 283 | std::copy(node_info.username.begin(), node_info.username.end(), | ||
| 284 | eapol_start.node.username.begin()); | ||
| 285 | |||
| 286 | // Note: The network_node_id and unknown bytes seem to be uninitialized in the NWM module. | ||
| 287 | // TODO(B3N30): The last 8 bytes seem to have a fixed value of 07 88 15 00 04 e9 13 00 in | ||
| 288 | // EAPoL-Start packets from different 3DSs to the same host during a Super Smash Bros. 4 game. | ||
| 289 | // Find out what that means. | ||
| 290 | |||
| 291 | std::vector<u8> eapol_buffer(sizeof(EAPoLStartPacket)); | ||
| 292 | std::memcpy(eapol_buffer.data(), &eapol_start, sizeof(eapol_start)); | ||
| 293 | |||
| 294 | std::vector<u8> buffer = GenerateLLCHeader(EtherType::EAPoL); | ||
| 295 | buffer.insert(buffer.end(), eapol_buffer.begin(), eapol_buffer.end()); | ||
| 296 | return buffer; | ||
| 297 | } | ||
| 298 | |||
| 299 | EtherType GetFrameEtherType(const std::vector<u8>& frame) { | ||
| 300 | LLCHeader header; | ||
| 301 | std::memcpy(&header, frame.data(), sizeof(header)); | ||
| 302 | |||
| 303 | u16 ethertype = header.protocol; | ||
| 304 | return static_cast<EtherType>(ethertype); | ||
| 305 | } | ||
| 306 | |||
| 307 | u16 GetEAPoLFrameType(const std::vector<u8>& frame) { | ||
| 308 | // Ignore the LLC header | ||
| 309 | u16_be eapol_type; | ||
| 310 | std::memcpy(&eapol_type, frame.data() + sizeof(LLCHeader), sizeof(eapol_type)); | ||
| 311 | return eapol_type; | ||
| 312 | } | ||
| 313 | |||
| 314 | NodeInfo DeserializeNodeInfoFromFrame(const std::vector<u8>& frame) { | ||
| 315 | EAPoLStartPacket eapol_start; | ||
| 316 | |||
| 317 | // Skip the LLC header | ||
| 318 | std::memcpy(&eapol_start, frame.data() + sizeof(LLCHeader), sizeof(eapol_start)); | ||
| 319 | |||
| 320 | NodeInfo node{}; | ||
| 321 | node.friend_code_seed = eapol_start.node.friend_code_seed; | ||
| 322 | |||
| 323 | std::copy(eapol_start.node.username.begin(), eapol_start.node.username.end(), | ||
| 324 | node.username.begin()); | ||
| 325 | |||
| 326 | return node; | ||
| 327 | } | ||
| 328 | |||
| 329 | NodeInfo DeserializeNodeInfo(const EAPoLNodeInfo& node) { | ||
| 330 | NodeInfo node_info{}; | ||
| 331 | node_info.friend_code_seed = node.friend_code_seed; | ||
| 332 | node_info.network_node_id = node.network_node_id; | ||
| 333 | |||
| 334 | std::copy(node.username.begin(), node.username.end(), node_info.username.begin()); | ||
| 335 | |||
| 336 | return node_info; | ||
| 337 | } | ||
| 338 | |||
| 339 | std::vector<u8> GenerateEAPoLLogoffFrame(const MacAddress& mac_address, u16 network_node_id, | ||
| 340 | const NodeList& nodes, u8 max_nodes, u8 total_nodes) { | ||
| 341 | EAPoLLogoffPacket eapol_logoff{}; | ||
| 342 | eapol_logoff.assigned_node_id = network_node_id; | ||
| 343 | eapol_logoff.connected_nodes = total_nodes; | ||
| 344 | eapol_logoff.max_nodes = max_nodes; | ||
| 345 | |||
| 346 | for (size_t index = 0; index < total_nodes; ++index) { | ||
| 347 | const auto& node_info = nodes[index]; | ||
| 348 | auto& node = eapol_logoff.nodes[index]; | ||
| 349 | |||
| 350 | node.friend_code_seed = node_info.friend_code_seed; | ||
| 351 | node.network_node_id = node_info.network_node_id; | ||
| 352 | |||
| 353 | std::copy(node_info.username.begin(), node_info.username.end(), node.username.begin()); | ||
| 354 | } | ||
| 355 | |||
| 356 | std::vector<u8> eapol_buffer(sizeof(EAPoLLogoffPacket)); | ||
| 357 | std::memcpy(eapol_buffer.data(), &eapol_logoff, sizeof(eapol_logoff)); | ||
| 358 | |||
| 359 | std::vector<u8> buffer = GenerateLLCHeader(EtherType::EAPoL); | ||
| 360 | buffer.insert(buffer.end(), eapol_buffer.begin(), eapol_buffer.end()); | ||
| 361 | return buffer; | ||
| 362 | } | ||
| 363 | |||
| 364 | EAPoLLogoffPacket ParseEAPoLLogoffFrame(const std::vector<u8>& frame) { | ||
| 365 | EAPoLLogoffPacket eapol_logoff; | ||
| 366 | |||
| 367 | // Skip the LLC header | ||
| 368 | std::memcpy(&eapol_logoff, frame.data() + sizeof(LLCHeader), sizeof(eapol_logoff)); | ||
| 369 | return eapol_logoff; | ||
| 370 | } | ||
| 371 | |||
| 372 | } // namespace NWM | ||
| 373 | } // namespace Service | ||
diff --git a/src/core/hle/service/nwm/uds_data.h b/src/core/hle/service/nwm/uds_data.h deleted file mode 100644 index 76bccb1bf..000000000 --- a/src/core/hle/service/nwm/uds_data.h +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/swap.h" | ||
| 11 | #include "core/hle/service/nwm/uds_beacon.h" | ||
| 12 | #include "core/hle/service/service.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace NWM { | ||
| 16 | |||
| 17 | enum class SAP : u8 { SNAPExtensionUsed = 0xAA }; | ||
| 18 | |||
| 19 | enum class PDUControl : u8 { UnnumberedInformation = 3 }; | ||
| 20 | |||
| 21 | enum class EtherType : u16 { SecureData = 0x876D, EAPoL = 0x888E }; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * 802.2 header, UDS packets always use SNAP for these headers, | ||
| 25 | * which means the dsap and ssap are always SNAPExtensionUsed (0xAA) | ||
| 26 | * and the OUI is always 0. | ||
| 27 | */ | ||
| 28 | struct LLCHeader { | ||
| 29 | u8 dsap = static_cast<u8>(SAP::SNAPExtensionUsed); | ||
| 30 | u8 ssap = static_cast<u8>(SAP::SNAPExtensionUsed); | ||
| 31 | u8 control = static_cast<u8>(PDUControl::UnnumberedInformation); | ||
| 32 | std::array<u8, 3> OUI = {}; | ||
| 33 | u16_be protocol; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static_assert(sizeof(LLCHeader) == 8, "LLCHeader has the wrong size"); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Nintendo SecureData header, every UDS packet contains one, | ||
| 40 | * it is used to store metadata about the transmission such as | ||
| 41 | * the source and destination network node ids. | ||
| 42 | */ | ||
| 43 | struct SecureDataHeader { | ||
| 44 | // TODO(Subv): It is likely that the first 4 bytes of this header are | ||
| 45 | // actually part of another container protocol. | ||
| 46 | u16_be protocol_size; | ||
| 47 | INSERT_PADDING_BYTES(2); | ||
| 48 | u16_be securedata_size; | ||
| 49 | u8 is_management; | ||
| 50 | u8 data_channel; | ||
| 51 | u16_be sequence_number; | ||
| 52 | u16_be dest_node_id; | ||
| 53 | u16_be src_node_id; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static_assert(sizeof(SecureDataHeader) == 14, "SecureDataHeader has the wrong size"); | ||
| 57 | |||
| 58 | /* | ||
| 59 | * The raw bytes of this structure are the CTR used in the encryption (AES-CTR) | ||
| 60 | * process used to generate the CCMP key for data frame encryption. | ||
| 61 | */ | ||
| 62 | struct DataFrameCryptoCTR { | ||
| 63 | u32_le wlan_comm_id; | ||
| 64 | u32_le network_id; | ||
| 65 | std::array<u8, 6> host_mac; | ||
| 66 | u16_le id; | ||
| 67 | }; | ||
| 68 | |||
| 69 | static_assert(sizeof(DataFrameCryptoCTR) == 16, "DataFrameCryptoCTR has the wrong size"); | ||
| 70 | |||
| 71 | struct EAPoLNodeInfo { | ||
| 72 | u64_be friend_code_seed; | ||
| 73 | std::array<u16_be, 10> username; | ||
| 74 | INSERT_PADDING_BYTES(4); | ||
| 75 | u16_be network_node_id; | ||
| 76 | INSERT_PADDING_BYTES(6); | ||
| 77 | }; | ||
| 78 | |||
| 79 | static_assert(sizeof(EAPoLNodeInfo) == 0x28, "EAPoLNodeInfo has the wrong size"); | ||
| 80 | |||
| 81 | constexpr u16 EAPoLStartMagic = 0x201; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Nintendo EAPoLStartPacket, is used to initaliaze a connection between client and host | ||
| 85 | */ | ||
| 86 | struct EAPoLStartPacket { | ||
| 87 | u16_be magic = EAPoLStartMagic; | ||
| 88 | u16_be association_id; | ||
| 89 | // This value is hardcoded to 1 in the NWM module. | ||
| 90 | u16_be unknown = 1; | ||
| 91 | INSERT_PADDING_BYTES(2); | ||
| 92 | EAPoLNodeInfo node; | ||
| 93 | }; | ||
| 94 | |||
| 95 | static_assert(sizeof(EAPoLStartPacket) == 0x30, "EAPoLStartPacket has the wrong size"); | ||
| 96 | |||
| 97 | constexpr u16 EAPoLLogoffMagic = 0x202; | ||
| 98 | |||
| 99 | struct EAPoLLogoffPacket { | ||
| 100 | u16_be magic = EAPoLLogoffMagic; | ||
| 101 | INSERT_PADDING_BYTES(2); | ||
| 102 | u16_be assigned_node_id; | ||
| 103 | MacAddress client_mac_address; | ||
| 104 | INSERT_PADDING_BYTES(6); | ||
| 105 | u8 connected_nodes; | ||
| 106 | u8 max_nodes; | ||
| 107 | INSERT_PADDING_BYTES(4); | ||
| 108 | |||
| 109 | std::array<EAPoLNodeInfo, UDSMaxNodes> nodes; | ||
| 110 | }; | ||
| 111 | |||
| 112 | static_assert(sizeof(EAPoLLogoffPacket) == 0x298, "EAPoLLogoffPacket has the wrong size"); | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Generates an unencrypted 802.11 data payload. | ||
| 116 | * @returns The generated frame payload. | ||
| 117 | */ | ||
| 118 | std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node, | ||
| 119 | u16 src_node, u16 sequence_number); | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Generates an unencrypted 802.11 data frame body with the EAPoL-Start format for UDS | ||
| 123 | * communication. | ||
| 124 | * @returns The generated frame body. | ||
| 125 | */ | ||
| 126 | std::vector<u8> GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node_info); | ||
| 127 | |||
| 128 | /* | ||
| 129 | * Returns the EtherType of the specified 802.11 frame. | ||
| 130 | */ | ||
| 131 | EtherType GetFrameEtherType(const std::vector<u8>& frame); | ||
| 132 | |||
| 133 | /* | ||
| 134 | * Returns the EAPoL type (Start / Logoff) of the specified 802.11 frame. | ||
| 135 | * Note: The frame *must* be an EAPoL frame. | ||
| 136 | */ | ||
| 137 | u16 GetEAPoLFrameType(const std::vector<u8>& frame); | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Returns a deserialized NodeInfo structure from the information inside an EAPoL-Start packet | ||
| 141 | * encapsulated in an 802.11 data frame. | ||
| 142 | */ | ||
| 143 | NodeInfo DeserializeNodeInfoFromFrame(const std::vector<u8>& frame); | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Returns a NodeInfo constructed from the data in the specified EAPoLNodeInfo. | ||
| 147 | */ | ||
| 148 | NodeInfo DeserializeNodeInfo(const EAPoLNodeInfo& node); | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Generates an unencrypted 802.11 data frame body with the EAPoL-Logoff format for UDS | ||
| 152 | * communication. | ||
| 153 | * @returns The generated frame body. | ||
| 154 | */ | ||
| 155 | std::vector<u8> GenerateEAPoLLogoffFrame(const MacAddress& mac_address, u16 network_node_id, | ||
| 156 | const NodeList& nodes, u8 max_nodes, u8 total_nodes); | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Returns a EAPoLLogoffPacket representing the specified 802.11-encapsulated data frame. | ||
| 160 | */ | ||
| 161 | EAPoLLogoffPacket ParseEAPoLLogoffFrame(const std::vector<u8>& frame); | ||
| 162 | |||
| 163 | } // namespace NWM | ||
| 164 | } // namespace Service | ||
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp deleted file mode 100644 index caa16f952..000000000 --- a/src/core/hle/service/pm_app.cpp +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/pm_app.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace PM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | {0x00010140, nullptr, "LaunchTitle"}, | ||
| 13 | {0x00020082, nullptr, "LaunchFIRM"}, | ||
| 14 | {0x00030080, nullptr, "TerminateApplication"}, | ||
| 15 | {0x00040100, nullptr, "TerminateTitle"}, | ||
| 16 | {0x000500C0, nullptr, "TerminateProcess"}, | ||
| 17 | {0x00060082, nullptr, "PrepareForReboot"}, | ||
| 18 | {0x00070042, nullptr, "GetFIRMLaunchParams"}, | ||
| 19 | {0x00080100, nullptr, "GetTitleExheaderFlags"}, | ||
| 20 | {0x00090042, nullptr, "SetFIRMLaunchParams"}, | ||
| 21 | {0x000A0140, nullptr, "SetAppResourceLimit"}, | ||
| 22 | {0x000B0140, nullptr, "GetAppResourceLimit"}, | ||
| 23 | {0x000C0080, nullptr, "UnregisterProcess"}, | ||
| 24 | {0x000D0240, nullptr, "LaunchTitleUpdate"}, | ||
| 25 | // clang-format on | ||
| 26 | }; | ||
| 27 | |||
| 28 | PM_APP::PM_APP() { | ||
| 29 | Register(FunctionTable); | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace PM | ||
| 33 | } // namespace Service | ||
diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h deleted file mode 100644 index 151c69f3d..000000000 --- a/src/core/hle/service/pm_app.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PM { | ||
| 11 | |||
| 12 | class PM_APP final : public Interface { | ||
| 13 | public: | ||
| 14 | PM_APP(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "pm:app"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace PM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp deleted file mode 100644 index a0b959797..000000000 --- a/src/core/hle/service/ptm/ptm.cpp +++ /dev/null | |||
| @@ -1,166 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/file_sys/errors.h" | ||
| 7 | #include "core/file_sys/file_backend.h" | ||
| 8 | #include "core/hle/service/fs/archive.h" | ||
| 9 | #include "core/hle/service/ptm/ptm.h" | ||
| 10 | #include "core/hle/service/ptm/ptm_gets.h" | ||
| 11 | #include "core/hle/service/ptm/ptm_play.h" | ||
| 12 | #include "core/hle/service/ptm/ptm_sets.h" | ||
| 13 | #include "core/hle/service/ptm/ptm_sysm.h" | ||
| 14 | #include "core/hle/service/ptm/ptm_u.h" | ||
| 15 | #include "core/hle/service/service.h" | ||
| 16 | #include "core/settings.h" | ||
| 17 | |||
| 18 | namespace Service { | ||
| 19 | namespace PTM { | ||
| 20 | |||
| 21 | /// Values for the default gamecoin.dat file | ||
| 22 | static const GameCoin default_game_coin = {0x4F00, 42, 0, 0, 0, 2014, 12, 29}; | ||
| 23 | |||
| 24 | /// Id of the SharedExtData archive used by the PTM process | ||
| 25 | static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; | ||
| 26 | |||
| 27 | static bool shell_open; | ||
| 28 | |||
| 29 | static bool battery_is_charging; | ||
| 30 | |||
| 31 | static bool pedometer_is_counting; | ||
| 32 | |||
| 33 | void GetAdapterState(Service::Interface* self) { | ||
| 34 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 0, 0); | ||
| 35 | |||
| 36 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 37 | rb.Push(RESULT_SUCCESS); | ||
| 38 | rb.Push(battery_is_charging); | ||
| 39 | |||
| 40 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 41 | } | ||
| 42 | |||
| 43 | void GetShellState(Service::Interface* self) { | ||
| 44 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 0, 0); | ||
| 45 | |||
| 46 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 47 | rb.Push(RESULT_SUCCESS); | ||
| 48 | rb.Push(shell_open); | ||
| 49 | } | ||
| 50 | |||
| 51 | void GetBatteryLevel(Service::Interface* self) { | ||
| 52 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x7, 0, 0); | ||
| 53 | |||
| 54 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 55 | rb.Push(RESULT_SUCCESS); | ||
| 56 | rb.Push(static_cast<u32>(ChargeLevels::CompletelyFull)); // Set to a completely full battery | ||
| 57 | |||
| 58 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 59 | } | ||
| 60 | |||
| 61 | void GetBatteryChargeState(Service::Interface* self) { | ||
| 62 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x8, 0, 0); | ||
| 63 | |||
| 64 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 65 | rb.Push(RESULT_SUCCESS); | ||
| 66 | rb.Push(battery_is_charging); | ||
| 67 | |||
| 68 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 69 | } | ||
| 70 | |||
| 71 | void GetPedometerState(Service::Interface* self) { | ||
| 72 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 0, 0); | ||
| 73 | |||
| 74 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 75 | rb.Push(RESULT_SUCCESS); | ||
| 76 | rb.Push(pedometer_is_counting); | ||
| 77 | |||
| 78 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 79 | } | ||
| 80 | |||
| 81 | void GetTotalStepCount(Service::Interface* self) { | ||
| 82 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 0, 0); | ||
| 83 | |||
| 84 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 85 | rb.Push(RESULT_SUCCESS); | ||
| 86 | rb.Push<u32>(0); | ||
| 87 | |||
| 88 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 89 | } | ||
| 90 | |||
| 91 | void GetSoftwareClosedFlag(Service::Interface* self) { | ||
| 92 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x80F, 0, 0); | ||
| 93 | |||
| 94 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||
| 95 | rb.Push(RESULT_SUCCESS); | ||
| 96 | rb.Push(false); | ||
| 97 | |||
| 98 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 99 | } | ||
| 100 | |||
| 101 | void CheckNew3DS(IPC::RequestBuilder& rb) { | ||
| 102 | const bool is_new_3ds = Settings::values.is_new_3ds; | ||
| 103 | |||
| 104 | if (is_new_3ds) { | ||
| 105 | LOG_CRITICAL(Service_PTM, "The option 'is_new_3ds' is enabled as part of the 'System' " | ||
| 106 | "settings. Citra does not fully support New 3DS emulation yet!"); | ||
| 107 | } | ||
| 108 | |||
| 109 | rb.Push(RESULT_SUCCESS); | ||
| 110 | rb.Push(is_new_3ds); | ||
| 111 | |||
| 112 | LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds)); | ||
| 113 | } | ||
| 114 | |||
| 115 | void CheckNew3DS(Service::Interface* self) { | ||
| 116 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x40A, 0, 0); // 0x040A0000 | ||
| 117 | CheckNew3DS(rb); | ||
| 118 | } | ||
| 119 | |||
| 120 | void Init() { | ||
| 121 | AddService(new PTM_Gets); | ||
| 122 | AddService(new PTM_Play); | ||
| 123 | AddService(new PTM_S); | ||
| 124 | AddService(new PTM_Sets); | ||
| 125 | AddService(new PTM_Sysm); | ||
| 126 | AddService(new PTM_U); | ||
| 127 | |||
| 128 | shell_open = true; | ||
| 129 | battery_is_charging = true; | ||
| 130 | pedometer_is_counting = false; | ||
| 131 | |||
| 132 | // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't | ||
| 133 | // exist | ||
| 134 | FileSys::Path archive_path(ptm_shared_extdata_id); | ||
| 135 | auto archive_result = | ||
| 136 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); | ||
| 137 | // If the archive didn't exist, create the files inside | ||
| 138 | if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { | ||
| 139 | // Format the archive to create the directories | ||
| 140 | Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, | ||
| 141 | FileSys::ArchiveFormatInfo(), archive_path); | ||
| 142 | // Open it again to get a valid archive now that the folder exists | ||
| 143 | archive_result = | ||
| 144 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); | ||
| 145 | ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); | ||
| 146 | |||
| 147 | FileSys::Path gamecoin_path("/gamecoin.dat"); | ||
| 148 | Service::FS::CreateFileInArchive(*archive_result, gamecoin_path, sizeof(GameCoin)); | ||
| 149 | FileSys::Mode open_mode = {}; | ||
| 150 | open_mode.write_flag.Assign(1); | ||
| 151 | // Open the file and write the default gamecoin information | ||
| 152 | auto gamecoin_result = | ||
| 153 | Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); | ||
| 154 | if (gamecoin_result.Succeeded()) { | ||
| 155 | auto gamecoin = std::move(gamecoin_result).Unwrap(); | ||
| 156 | gamecoin->backend->Write(0, sizeof(GameCoin), true, | ||
| 157 | reinterpret_cast<const u8*>(&default_game_coin)); | ||
| 158 | gamecoin->backend->Close(); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | void Shutdown() {} | ||
| 164 | |||
| 165 | } // namespace PTM | ||
| 166 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h deleted file mode 100644 index e17e59835..000000000 --- a/src/core/hle/service/ptm/ptm.h +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | |||
| 12 | class Interface; | ||
| 13 | |||
| 14 | namespace PTM { | ||
| 15 | |||
| 16 | /// Charge levels used by PTM functions | ||
| 17 | enum class ChargeLevels : u32 { | ||
| 18 | CriticalBattery = 1, | ||
| 19 | LowBattery = 2, | ||
| 20 | HalfFull = 3, | ||
| 21 | MostlyFull = 4, | ||
| 22 | CompletelyFull = 5, | ||
| 23 | }; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Represents the gamecoin file structure in the SharedExtData archive | ||
| 27 | * More information in 3dbrew | ||
| 28 | * (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) | ||
| 29 | */ | ||
| 30 | struct GameCoin { | ||
| 31 | u32 magic; ///< Magic number: 0x4F00 | ||
| 32 | u16 total_coins; ///< Total Play Coins | ||
| 33 | u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. | ||
| 34 | u32 step_count; ///< Total step count at the time a new Play Coin was obtained. | ||
| 35 | u32 last_step_count; ///< Step count for the day the last Play Coin was obtained | ||
| 36 | u16 year; | ||
| 37 | u8 month; | ||
| 38 | u8 day; | ||
| 39 | }; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * It is unknown if GetAdapterState is the same as GetBatteryChargeState, | ||
| 43 | * it is likely to just be a duplicate function of GetBatteryChargeState | ||
| 44 | * that controls another part of the HW. | ||
| 45 | * PTM::GetAdapterState service function | ||
| 46 | * Outputs: | ||
| 47 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 48 | * 2 : Output of function, 0 = not charging, 1 = charging. | ||
| 49 | */ | ||
| 50 | void GetAdapterState(Interface* self); | ||
| 51 | |||
| 52 | /** | ||
| 53 | * PTM::GetShellState service function. | ||
| 54 | * Outputs: | ||
| 55 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 56 | * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0) | ||
| 57 | */ | ||
| 58 | void GetShellState(Interface* self); | ||
| 59 | |||
| 60 | /** | ||
| 61 | * PTM::GetBatteryLevel service function | ||
| 62 | * Outputs: | ||
| 63 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 64 | * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery, | ||
| 65 | * 3 = half full battery, 2 = low battery, 1 = critical battery. | ||
| 66 | */ | ||
| 67 | void GetBatteryLevel(Interface* self); | ||
| 68 | |||
| 69 | /** | ||
| 70 | * PTM::GetBatteryChargeState service function | ||
| 71 | * Outputs: | ||
| 72 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 73 | * 2 : Output of function, 0 = not charging, 1 = charging. | ||
| 74 | */ | ||
| 75 | void GetBatteryChargeState(Interface* self); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * PTM::GetPedometerState service function | ||
| 79 | * Outputs: | ||
| 80 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 81 | * 2 : Output of function, 0 = not counting steps, 1 = counting steps. | ||
| 82 | */ | ||
| 83 | void GetPedometerState(Interface* self); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * PTM::GetTotalStepCount service function | ||
| 87 | * Outputs: | ||
| 88 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 89 | * 2 : Output of function, * = total step count | ||
| 90 | */ | ||
| 91 | void GetTotalStepCount(Interface* self); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * PTM::GetSoftwareClosedFlag service function | ||
| 95 | * Outputs: | ||
| 96 | * 1: Result code, 0 on success, otherwise error code | ||
| 97 | * 2: Whether or not the "software closed" dialog was requested by the last FIRM | ||
| 98 | * and should be displayed. | ||
| 99 | */ | ||
| 100 | void GetSoftwareClosedFlag(Interface* self); | ||
| 101 | |||
| 102 | /** | ||
| 103 | * PTM::CheckNew3DS service function | ||
| 104 | * Outputs: | ||
| 105 | * 1: Result code, 0 on success, otherwise error code | ||
| 106 | * 2: u8 output: 0 = Old3DS, 1 = New3DS. | ||
| 107 | */ | ||
| 108 | void CheckNew3DS(Interface* self); | ||
| 109 | void CheckNew3DS(IPC::RequestBuilder& rb); | ||
| 110 | |||
| 111 | /// Initialize the PTM service | ||
| 112 | void Init(); | ||
| 113 | |||
| 114 | /// Shutdown the PTM service | ||
| 115 | void Shutdown(); | ||
| 116 | |||
| 117 | } // namespace PTM | ||
| 118 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_gets.cpp b/src/core/hle/service/ptm/ptm_gets.cpp deleted file mode 100644 index b23e508d6..000000000 --- a/src/core/hle/service/ptm/ptm_gets.cpp +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ptm/ptm.h" | ||
| 6 | #include "core/hle/service/ptm/ptm_gets.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace PTM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // ptm:u common commands | ||
| 13 | {0x00010002, nullptr, "RegisterAlarmClient"}, | ||
| 14 | {0x00020080, nullptr, "SetRtcAlarm"}, | ||
| 15 | {0x00030000, nullptr, "GetRtcAlarm"}, | ||
| 16 | {0x00040000, nullptr, "CancelRtcAlarm"}, | ||
| 17 | {0x00050000, GetAdapterState, "GetAdapterState"}, | ||
| 18 | {0x00060000, GetShellState, "GetShellState"}, | ||
| 19 | {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, | ||
| 20 | {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, | ||
| 21 | {0x00090000, nullptr, "GetPedometerState"}, | ||
| 22 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | ||
| 23 | {0x000B00C2, nullptr, "GetStepHistory"}, | ||
| 24 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, | ||
| 25 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | ||
| 26 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | ||
| 27 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | ||
| 28 | // ptm:gets | ||
| 29 | {0x04010000, nullptr, "GetSystemTime"}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | PTM_Gets::PTM_Gets() { | ||
| 33 | Register(FunctionTable); | ||
| 34 | } | ||
| 35 | |||
| 36 | } // namespace PTM | ||
| 37 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_gets.h b/src/core/hle/service/ptm/ptm_gets.h deleted file mode 100644 index 5552c9eff..000000000 --- a/src/core/hle/service/ptm/ptm_gets.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PTM { | ||
| 11 | |||
| 12 | class PTM_Gets final : public Interface { | ||
| 13 | public: | ||
| 14 | PTM_Gets(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ptm:gets"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace PTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp deleted file mode 100644 index bcb00e0d4..000000000 --- a/src/core/hle/service/ptm/ptm_play.cpp +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ptm/ptm.h" | ||
| 6 | #include "core/hle/service/ptm/ptm_play.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace PTM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // ptm:u common commands | ||
| 13 | {0x00010002, nullptr, "RegisterAlarmClient"}, | ||
| 14 | {0x00020080, nullptr, "SetRtcAlarm"}, | ||
| 15 | {0x00030000, nullptr, "GetRtcAlarm"}, | ||
| 16 | {0x00040000, nullptr, "CancelRtcAlarm"}, | ||
| 17 | {0x00050000, GetAdapterState, "GetAdapterState"}, | ||
| 18 | {0x00060000, GetShellState, "GetShellState"}, | ||
| 19 | {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, | ||
| 20 | {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, | ||
| 21 | {0x00090000, nullptr, "GetPedometerState"}, | ||
| 22 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | ||
| 23 | {0x000B00C2, nullptr, "GetStepHistory"}, | ||
| 24 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, | ||
| 25 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | ||
| 26 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | ||
| 27 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | ||
| 28 | // ptm:play | ||
| 29 | {0x08070082, nullptr, "GetPlayHistory"}, | ||
| 30 | {0x08080000, nullptr, "GetPlayHistoryStart"}, | ||
| 31 | {0x08090000, nullptr, "GetPlayHistoryLength"}, | ||
| 32 | {0x080B0080, nullptr, "CalcPlayHistoryStart"}, | ||
| 33 | }; | ||
| 34 | |||
| 35 | PTM_Play::PTM_Play() { | ||
| 36 | Register(FunctionTable); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace PTM | ||
| 40 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/ptm/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h deleted file mode 100644 index 663faabee..000000000 --- a/src/core/hle/service/ptm/ptm_play.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PTM { | ||
| 11 | |||
| 12 | class PTM_Play final : public Interface { | ||
| 13 | public: | ||
| 14 | PTM_Play(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ptm:play"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace PTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_sets.cpp b/src/core/hle/service/ptm/ptm_sets.cpp deleted file mode 100644 index a8c6cf227..000000000 --- a/src/core/hle/service/ptm/ptm_sets.cpp +++ /dev/null | |||
| @@ -1,20 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ptm/ptm_sets.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace PTM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // Note that this service does not have access to ptm:u's common commands | ||
| 12 | {0x00010080, nullptr, "SetSystemTime"}, | ||
| 13 | }; | ||
| 14 | |||
| 15 | PTM_Sets::PTM_Sets() { | ||
| 16 | Register(FunctionTable); | ||
| 17 | } | ||
| 18 | |||
| 19 | } // namespace PTM | ||
| 20 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_sets.h b/src/core/hle/service/ptm/ptm_sets.h deleted file mode 100644 index d33b047e5..000000000 --- a/src/core/hle/service/ptm/ptm_sets.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PTM { | ||
| 11 | |||
| 12 | class PTM_Sets final : public Interface { | ||
| 13 | public: | ||
| 14 | PTM_Sets(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ptm:sets"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace PTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp deleted file mode 100644 index f95dfdbb1..000000000 --- a/src/core/hle/service/ptm/ptm_sysm.cpp +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ptm/ptm.h" | ||
| 6 | #include "core/hle/service/ptm/ptm_sysm.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace PTM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | // ptm:u common commands | ||
| 13 | {0x00010002, nullptr, "RegisterAlarmClient"}, | ||
| 14 | {0x00020080, nullptr, "SetRtcAlarm"}, | ||
| 15 | {0x00030000, nullptr, "GetRtcAlarm"}, | ||
| 16 | {0x00040000, nullptr, "CancelRtcAlarm"}, | ||
| 17 | {0x00050000, GetAdapterState, "GetAdapterState"}, | ||
| 18 | {0x00060000, GetShellState, "GetShellState"}, | ||
| 19 | {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, | ||
| 20 | {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, | ||
| 21 | {0x00090000, nullptr, "GetPedometerState"}, | ||
| 22 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | ||
| 23 | {0x000B00C2, nullptr, "GetStepHistory"}, | ||
| 24 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, | ||
| 25 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | ||
| 26 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | ||
| 27 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | ||
| 28 | // ptm:sysm | ||
| 29 | {0x040100C0, nullptr, "SetRtcAlarmEx"}, | ||
| 30 | {0x04020042, nullptr, "ReplySleepQuery"}, | ||
| 31 | {0x04030042, nullptr, "NotifySleepPreparationComplete"}, | ||
| 32 | {0x04040102, nullptr, "SetWakeupTrigger"}, | ||
| 33 | {0x04050000, nullptr, "GetAwakeReason"}, | ||
| 34 | {0x04060000, nullptr, "RequestSleep"}, | ||
| 35 | {0x040700C0, nullptr, "ShutdownAsync"}, | ||
| 36 | {0x04080000, nullptr, "Awake"}, | ||
| 37 | {0x04090080, nullptr, "RebootAsync"}, | ||
| 38 | {0x040A0000, CheckNew3DS, "CheckNew3DS"}, | ||
| 39 | {0x08010640, nullptr, "SetInfoLEDPattern"}, | ||
| 40 | {0x08020040, nullptr, "SetInfoLEDPatternHeader"}, | ||
| 41 | {0x08030000, nullptr, "GetInfoLEDStatus"}, | ||
| 42 | {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"}, | ||
| 43 | {0x08050000, nullptr, "ClearStepHistory"}, | ||
| 44 | {0x080600C2, nullptr, "SetStepHistory"}, | ||
| 45 | {0x08070082, nullptr, "GetPlayHistory"}, | ||
| 46 | {0x08080000, nullptr, "GetPlayHistoryStart"}, | ||
| 47 | {0x08090000, nullptr, "GetPlayHistoryLength"}, | ||
| 48 | {0x080A0000, nullptr, "ClearPlayHistory"}, | ||
| 49 | {0x080B0080, nullptr, "CalcPlayHistoryStart"}, | ||
| 50 | {0x080C0080, nullptr, "SetUserTime"}, | ||
| 51 | {0x080D0000, nullptr, "InvalidateSystemTime"}, | ||
| 52 | {0x080E0140, nullptr, "NotifyPlayEvent"}, | ||
| 53 | {0x080F0000, GetSoftwareClosedFlag, "GetSoftwareClosedFlag"}, | ||
| 54 | {0x08100000, nullptr, "ClearSoftwareClosedFlag"}, | ||
| 55 | {0x08110000, GetShellState, "GetShellState"}, | ||
| 56 | {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, | ||
| 57 | {0x08130000, nullptr, "FormatSavedata"}, | ||
| 58 | {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}, | ||
| 59 | {0x08180040, nullptr, "ConfigureNew3DSCPU"}, | ||
| 60 | }; | ||
| 61 | |||
| 62 | PTM_S::PTM_S() { | ||
| 63 | Register(FunctionTable); | ||
| 64 | } | ||
| 65 | |||
| 66 | PTM_Sysm::PTM_Sysm() { | ||
| 67 | Register(FunctionTable); | ||
| 68 | } | ||
| 69 | |||
| 70 | } // namespace PTM | ||
| 71 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h deleted file mode 100644 index 8afcebbba..000000000 --- a/src/core/hle/service/ptm/ptm_sysm.h +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PTM { | ||
| 11 | |||
| 12 | class PTM_S final : public Interface { | ||
| 13 | public: | ||
| 14 | PTM_S(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ptm:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | class PTM_Sysm final : public Interface { | ||
| 22 | public: | ||
| 23 | PTM_Sysm(); | ||
| 24 | |||
| 25 | std::string GetPortName() const override { | ||
| 26 | return "ptm:sysm"; | ||
| 27 | } | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace PTM | ||
| 31 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp deleted file mode 100644 index 696a58a36..000000000 --- a/src/core/hle/service/ptm/ptm_u.cpp +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ptm/ptm.h" | ||
| 6 | #include "core/hle/service/ptm/ptm_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace PTM { | ||
| 10 | |||
| 11 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 12 | {0x00010002, nullptr, "RegisterAlarmClient"}, | ||
| 13 | {0x00020080, nullptr, "SetRtcAlarm"}, | ||
| 14 | {0x00030000, nullptr, "GetRtcAlarm"}, | ||
| 15 | {0x00040000, nullptr, "CancelRtcAlarm"}, | ||
| 16 | {0x00050000, GetAdapterState, "GetAdapterState"}, | ||
| 17 | {0x00060000, GetShellState, "GetShellState"}, | ||
| 18 | {0x00070000, GetBatteryLevel, "GetBatteryLevel"}, | ||
| 19 | {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"}, | ||
| 20 | {0x00090000, GetPedometerState, "GetPedometerState"}, | ||
| 21 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | ||
| 22 | {0x000B00C2, nullptr, "GetStepHistory"}, | ||
| 23 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, | ||
| 24 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | ||
| 25 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | ||
| 26 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | ||
| 27 | }; | ||
| 28 | |||
| 29 | PTM_U::PTM_U() { | ||
| 30 | Register(FunctionTable); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace PTM | ||
| 34 | } // namespace Service | ||
diff --git a/src/core/hle/service/ptm/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h deleted file mode 100644 index 7b75d6e49..000000000 --- a/src/core/hle/service/ptm/ptm_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace PTM { | ||
| 11 | |||
| 12 | class PTM_U final : public Interface { | ||
| 13 | public: | ||
| 14 | PTM_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ptm:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace PTM | ||
| 22 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/qtm/qtm.cpp b/src/core/hle/service/qtm/qtm.cpp deleted file mode 100644 index f11542263..000000000 --- a/src/core/hle/service/qtm/qtm.cpp +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/qtm/qtm.h" | ||
| 6 | #include "core/hle/service/qtm/qtm_s.h" | ||
| 7 | #include "core/hle/service/qtm/qtm_sp.h" | ||
| 8 | #include "core/hle/service/qtm/qtm_u.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace QTM { | ||
| 13 | |||
| 14 | void Init() { | ||
| 15 | AddService(new QTM_S()); | ||
| 16 | AddService(new QTM_SP()); | ||
| 17 | AddService(new QTM_U()); | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace QTM | ||
| 21 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm.h b/src/core/hle/service/qtm/qtm.h deleted file mode 100644 index 33b774c79..000000000 --- a/src/core/hle/service/qtm/qtm.h +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace QTM { | ||
| 9 | |||
| 10 | /// Initializes all QTM services. | ||
| 11 | void Init(); | ||
| 12 | |||
| 13 | } // namespace QTM | ||
| 14 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_s.cpp b/src/core/hle/service/qtm/qtm_s.cpp deleted file mode 100644 index ad7df24a0..000000000 --- a/src/core/hle/service/qtm/qtm_s.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/qtm/qtm_s.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace QTM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | // qtm common commands | ||
| 13 | {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, | ||
| 14 | {0x00020080, nullptr, "GetHeadtrackingInfo"}, | ||
| 15 | // clang-format on | ||
| 16 | }; | ||
| 17 | |||
| 18 | QTM_S::QTM_S() { | ||
| 19 | Register(FunctionTable); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace QTM | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h deleted file mode 100644 index e66138ed0..000000000 --- a/src/core/hle/service/qtm/qtm_s.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace QTM { | ||
| 11 | |||
| 12 | class QTM_S final : public Interface { | ||
| 13 | public: | ||
| 14 | QTM_S(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "qtm:s"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace QTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_sp.cpp b/src/core/hle/service/qtm/qtm_sp.cpp deleted file mode 100644 index 6e0695d34..000000000 --- a/src/core/hle/service/qtm/qtm_sp.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/qtm/qtm_sp.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace QTM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | // qtm common commands | ||
| 13 | {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, | ||
| 14 | {0x00020080, nullptr, "GetHeadtrackingInfo"}, | ||
| 15 | // clang-format on | ||
| 16 | }; | ||
| 17 | |||
| 18 | QTM_SP::QTM_SP() { | ||
| 19 | Register(FunctionTable); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace QTM | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h deleted file mode 100644 index 0ae0618fc..000000000 --- a/src/core/hle/service/qtm/qtm_sp.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace QTM { | ||
| 11 | |||
| 12 | class QTM_SP final : public Interface { | ||
| 13 | public: | ||
| 14 | QTM_SP(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "qtm:sp"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace QTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_u.cpp b/src/core/hle/service/qtm/qtm_u.cpp deleted file mode 100644 index a0f808432..000000000 --- a/src/core/hle/service/qtm/qtm_u.cpp +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/qtm/qtm_u.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace QTM { | ||
| 9 | |||
| 10 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 11 | // clang-format off | ||
| 12 | // qtm common commands | ||
| 13 | {0x00010080, nullptr, "GetHeadtrackingInfoRaw"}, | ||
| 14 | {0x00020080, nullptr, "GetHeadtrackingInfo"}, | ||
| 15 | // clang-format on | ||
| 16 | }; | ||
| 17 | |||
| 18 | QTM_U::QTM_U() { | ||
| 19 | Register(FunctionTable); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace QTM | ||
| 23 | } // namespace Service | ||
diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h deleted file mode 100644 index 1ed4c0adc..000000000 --- a/src/core/hle/service/qtm/qtm_u.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace QTM { | ||
| 11 | |||
| 12 | class QTM_U final : public Interface { | ||
| 13 | public: | ||
| 14 | QTM_U(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "qtm:u"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace QTM | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index f267aad74..afd27d446 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -12,43 +12,17 @@ | |||
| 12 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/server_port.h" | 13 | #include "core/hle/kernel/server_port.h" |
| 14 | #include "core/hle/kernel/server_session.h" | 14 | #include "core/hle/kernel/server_session.h" |
| 15 | #include "core/hle/service/ac/ac.h" | 15 | #include "core/hle/kernel/handle_table.h" |
| 16 | #include "core/hle/service/act/act.h" | ||
| 17 | #include "core/hle/service/am/am.h" | ||
| 18 | #include "core/hle/service/apt/apt.h" | ||
| 19 | #include "core/hle/service/boss/boss.h" | ||
| 20 | #include "core/hle/service/cam/cam.h" | ||
| 21 | #include "core/hle/service/cecd/cecd.h" | ||
| 22 | #include "core/hle/service/cfg/cfg.h" | 16 | #include "core/hle/service/cfg/cfg.h" |
| 23 | #include "core/hle/service/csnd_snd.h" | ||
| 24 | #include "core/hle/service/dlp/dlp.h" | ||
| 25 | #include "core/hle/service/dsp_dsp.h" | 17 | #include "core/hle/service/dsp_dsp.h" |
| 26 | #include "core/hle/service/err_f.h" | ||
| 27 | #include "core/hle/service/frd/frd.h" | ||
| 28 | #include "core/hle/service/fs/archive.h" | 18 | #include "core/hle/service/fs/archive.h" |
| 29 | #include "core/hle/service/gsp_gpu.h" | 19 | #include "core/hle/service/gsp_gpu.h" |
| 30 | #include "core/hle/service/gsp_lcd.h" | 20 | #include "core/hle/service/gsp_lcd.h" |
| 31 | #include "core/hle/service/hid/hid.h" | 21 | #include "core/hle/service/hid/hid.h" |
| 32 | #include "core/hle/service/http_c.h" | ||
| 33 | #include "core/hle/service/ir/ir.h" | ||
| 34 | #include "core/hle/service/ldr_ro/ldr_ro.h" | ||
| 35 | #include "core/hle/service/mic_u.h" | ||
| 36 | #include "core/hle/service/mvd/mvd.h" | ||
| 37 | #include "core/hle/service/ndm/ndm.h" | ||
| 38 | #include "core/hle/service/news/news.h" | ||
| 39 | #include "core/hle/service/nfc/nfc.h" | ||
| 40 | #include "core/hle/service/nim/nim.h" | ||
| 41 | #include "core/hle/service/ns/ns.h" | 22 | #include "core/hle/service/ns/ns.h" |
| 42 | #include "core/hle/service/nwm/nwm.h" | ||
| 43 | #include "core/hle/service/pm_app.h" | ||
| 44 | #include "core/hle/service/ptm/ptm.h" | ||
| 45 | #include "core/hle/service/qtm/qtm.h" | ||
| 46 | #include "core/hle/service/service.h" | 23 | #include "core/hle/service/service.h" |
| 47 | #include "core/hle/service/sm/sm.h" | 24 | #include "core/hle/service/sm/sm.h" |
| 48 | #include "core/hle/service/sm/srv.h" | 25 | #include "core/hle/service/sm/srv.h" |
| 49 | #include "core/hle/service/soc_u.h" | ||
| 50 | #include "core/hle/service/ssl_c.h" | ||
| 51 | #include "core/hle/service/y2r_u.h" | ||
| 52 | 26 | ||
| 53 | using Kernel::ClientPort; | 27 | using Kernel::ClientPort; |
| 54 | using Kernel::ServerPort; | 28 | using Kernel::ServerPort; |
| @@ -217,63 +191,21 @@ void Init() { | |||
| 217 | 191 | ||
| 218 | NS::InstallInterfaces(*SM::g_service_manager); | 192 | NS::InstallInterfaces(*SM::g_service_manager); |
| 219 | 193 | ||
| 220 | AddNamedPort(new ERR::ERR_F); | ||
| 221 | |||
| 222 | FS::ArchiveInit(); | 194 | FS::ArchiveInit(); |
| 223 | AC::Init(); | ||
| 224 | ACT::Init(); | ||
| 225 | AM::Init(); | ||
| 226 | APT::Init(); | ||
| 227 | BOSS::Init(); | ||
| 228 | CAM::Init(); | ||
| 229 | CECD::Init(); | ||
| 230 | CFG::Init(); | 195 | CFG::Init(); |
| 231 | DLP::Init(); | ||
| 232 | FRD::Init(); | ||
| 233 | HID::Init(); | 196 | HID::Init(); |
| 234 | IR::Init(); | 197 | |
| 235 | MVD::Init(); | ||
| 236 | NDM::Init(); | ||
| 237 | NEWS::Init(); | ||
| 238 | NFC::Init(); | ||
| 239 | NIM::Init(); | ||
| 240 | NWM::Init(); | ||
| 241 | PTM::Init(); | ||
| 242 | QTM::Init(); | ||
| 243 | |||
| 244 | AddService(new CSND::CSND_SND); | ||
| 245 | AddService(new DSP_DSP::Interface); | 198 | AddService(new DSP_DSP::Interface); |
| 246 | AddService(new GSP::GSP_GPU); | 199 | AddService(new GSP::GSP_GPU); |
| 247 | AddService(new GSP::GSP_LCD); | 200 | AddService(new GSP::GSP_LCD); |
| 248 | AddService(new HTTP::HTTP_C); | ||
| 249 | AddService(new LDR::LDR_RO); | ||
| 250 | AddService(new MIC::MIC_U); | ||
| 251 | AddService(new PM::PM_APP); | ||
| 252 | AddService(new SOC::SOC_U); | ||
| 253 | AddService(new SSL::SSL_C); | ||
| 254 | AddService(new Y2R::Y2R_U); | ||
| 255 | 201 | ||
| 256 | LOG_DEBUG(Service, "initialized OK"); | 202 | LOG_DEBUG(Service, "initialized OK"); |
| 257 | } | 203 | } |
| 258 | 204 | ||
| 259 | /// Shutdown ServiceManager | 205 | /// Shutdown ServiceManager |
| 260 | void Shutdown() { | 206 | void Shutdown() { |
| 261 | PTM::Shutdown(); | ||
| 262 | NFC::Shutdown(); | ||
| 263 | NIM::Shutdown(); | ||
| 264 | NEWS::Shutdown(); | ||
| 265 | NDM::Shutdown(); | ||
| 266 | IR::Shutdown(); | ||
| 267 | HID::Shutdown(); | 207 | HID::Shutdown(); |
| 268 | FRD::Shutdown(); | ||
| 269 | DLP::Shutdown(); | ||
| 270 | CFG::Shutdown(); | 208 | CFG::Shutdown(); |
| 271 | CECD::Shutdown(); | ||
| 272 | CAM::Shutdown(); | ||
| 273 | BOSS::Shutdown(); | ||
| 274 | APT::Shutdown(); | ||
| 275 | AM::Shutdown(); | ||
| 276 | AC::Shutdown(); | ||
| 277 | FS::ArchiveShutdown(); | 209 | FS::ArchiveShutdown(); |
| 278 | 210 | ||
| 279 | SM::g_service_manager = nullptr; | 211 | SM::g_service_manager = nullptr; |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp deleted file mode 100644 index 3d215d42d..000000000 --- a/src/core/hle/service/soc_u.cpp +++ /dev/null | |||
| @@ -1,919 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstring> | ||
| 7 | #include <unordered_map> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/scope_exit.h" | ||
| 14 | #include "core/hle/ipc.h" | ||
| 15 | #include "core/hle/kernel/server_session.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | #include "core/hle/service/soc_u.h" | ||
| 18 | #include "core/memory.h" | ||
| 19 | |||
| 20 | #ifdef _WIN32 | ||
| 21 | #include <winsock2.h> | ||
| 22 | #include <ws2tcpip.h> | ||
| 23 | |||
| 24 | // MinGW does not define several errno constants | ||
| 25 | #ifndef _MSC_VER | ||
| 26 | #define EBADMSG 104 | ||
| 27 | #define ENODATA 120 | ||
| 28 | #define ENOMSG 122 | ||
| 29 | #define ENOSR 124 | ||
| 30 | #define ENOSTR 125 | ||
| 31 | #define ETIME 137 | ||
| 32 | #define EIDRM 2001 | ||
| 33 | #define ENOLINK 2002 | ||
| 34 | #endif // _MSC_VER | ||
| 35 | #else | ||
| 36 | #include <cerrno> | ||
| 37 | #include <fcntl.h> | ||
| 38 | #include <netdb.h> | ||
| 39 | #include <netinet/in.h> | ||
| 40 | #include <poll.h> | ||
| 41 | #include <sys/socket.h> | ||
| 42 | #include <unistd.h> | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #ifdef _WIN32 | ||
| 46 | #define WSAEAGAIN WSAEWOULDBLOCK | ||
| 47 | #define WSAEMULTIHOP -1 // Invalid dummy value | ||
| 48 | #define ERRNO(x) WSA##x | ||
| 49 | #define GET_ERRNO WSAGetLastError() | ||
| 50 | #define poll(x, y, z) WSAPoll(x, y, z); | ||
| 51 | #else | ||
| 52 | #define ERRNO(x) x | ||
| 53 | #define GET_ERRNO errno | ||
| 54 | #define closesocket(x) close(x) | ||
| 55 | #endif | ||
| 56 | |||
| 57 | namespace Service { | ||
| 58 | namespace SOC { | ||
| 59 | |||
| 60 | const s32 SOCKET_ERROR_VALUE = -1; | ||
| 61 | |||
| 62 | /// Holds the translation from system network errors to 3DS network errors | ||
| 63 | static const std::unordered_map<int, int> error_map = {{ | ||
| 64 | {E2BIG, 1}, | ||
| 65 | {ERRNO(EACCES), 2}, | ||
| 66 | {ERRNO(EADDRINUSE), 3}, | ||
| 67 | {ERRNO(EADDRNOTAVAIL), 4}, | ||
| 68 | {ERRNO(EAFNOSUPPORT), 5}, | ||
| 69 | {ERRNO(EAGAIN), 6}, | ||
| 70 | {ERRNO(EALREADY), 7}, | ||
| 71 | {ERRNO(EBADF), 8}, | ||
| 72 | {EBADMSG, 9}, | ||
| 73 | {EBUSY, 10}, | ||
| 74 | {ECANCELED, 11}, | ||
| 75 | {ECHILD, 12}, | ||
| 76 | {ERRNO(ECONNABORTED), 13}, | ||
| 77 | {ERRNO(ECONNREFUSED), 14}, | ||
| 78 | {ERRNO(ECONNRESET), 15}, | ||
| 79 | {EDEADLK, 16}, | ||
| 80 | {ERRNO(EDESTADDRREQ), 17}, | ||
| 81 | {EDOM, 18}, | ||
| 82 | {ERRNO(EDQUOT), 19}, | ||
| 83 | {EEXIST, 20}, | ||
| 84 | {ERRNO(EFAULT), 21}, | ||
| 85 | {EFBIG, 22}, | ||
| 86 | {ERRNO(EHOSTUNREACH), 23}, | ||
| 87 | {EIDRM, 24}, | ||
| 88 | {EILSEQ, 25}, | ||
| 89 | {ERRNO(EINPROGRESS), 26}, | ||
| 90 | {ERRNO(EINTR), 27}, | ||
| 91 | {ERRNO(EINVAL), 28}, | ||
| 92 | {EIO, 29}, | ||
| 93 | {ERRNO(EISCONN), 30}, | ||
| 94 | {EISDIR, 31}, | ||
| 95 | {ERRNO(ELOOP), 32}, | ||
| 96 | {ERRNO(EMFILE), 33}, | ||
| 97 | {EMLINK, 34}, | ||
| 98 | {ERRNO(EMSGSIZE), 35}, | ||
| 99 | {ERRNO(EMULTIHOP), 36}, | ||
| 100 | {ERRNO(ENAMETOOLONG), 37}, | ||
| 101 | {ERRNO(ENETDOWN), 38}, | ||
| 102 | {ERRNO(ENETRESET), 39}, | ||
| 103 | {ERRNO(ENETUNREACH), 40}, | ||
| 104 | {ENFILE, 41}, | ||
| 105 | {ERRNO(ENOBUFS), 42}, | ||
| 106 | #ifdef ENODATA | ||
| 107 | {ENODATA, 43}, | ||
| 108 | #endif | ||
| 109 | {ENODEV, 44}, | ||
| 110 | {ENOENT, 45}, | ||
| 111 | {ENOEXEC, 46}, | ||
| 112 | {ENOLCK, 47}, | ||
| 113 | {ENOLINK, 48}, | ||
| 114 | {ENOMEM, 49}, | ||
| 115 | {ENOMSG, 50}, | ||
| 116 | {ERRNO(ENOPROTOOPT), 51}, | ||
| 117 | {ENOSPC, 52}, | ||
| 118 | #ifdef ENOSR | ||
| 119 | {ENOSR, 53}, | ||
| 120 | #endif | ||
| 121 | #ifdef ENOSTR | ||
| 122 | {ENOSTR, 54}, | ||
| 123 | #endif | ||
| 124 | {ENOSYS, 55}, | ||
| 125 | {ERRNO(ENOTCONN), 56}, | ||
| 126 | {ENOTDIR, 57}, | ||
| 127 | {ERRNO(ENOTEMPTY), 58}, | ||
| 128 | {ERRNO(ENOTSOCK), 59}, | ||
| 129 | {ENOTSUP, 60}, | ||
| 130 | {ENOTTY, 61}, | ||
| 131 | {ENXIO, 62}, | ||
| 132 | {ERRNO(EOPNOTSUPP), 63}, | ||
| 133 | {EOVERFLOW, 64}, | ||
| 134 | {EPERM, 65}, | ||
| 135 | {EPIPE, 66}, | ||
| 136 | {EPROTO, 67}, | ||
| 137 | {ERRNO(EPROTONOSUPPORT), 68}, | ||
| 138 | {ERRNO(EPROTOTYPE), 69}, | ||
| 139 | {ERANGE, 70}, | ||
| 140 | {EROFS, 71}, | ||
| 141 | {ESPIPE, 72}, | ||
| 142 | {ESRCH, 73}, | ||
| 143 | {ERRNO(ESTALE), 74}, | ||
| 144 | #ifdef ETIME | ||
| 145 | {ETIME, 75}, | ||
| 146 | #endif | ||
| 147 | {ERRNO(ETIMEDOUT), 76}, | ||
| 148 | }}; | ||
| 149 | |||
| 150 | /// Converts a network error from platform-specific to 3ds-specific | ||
| 151 | static int TranslateError(int error) { | ||
| 152 | auto found = error_map.find(error); | ||
| 153 | if (found != error_map.end()) | ||
| 154 | return -found->second; | ||
| 155 | |||
| 156 | return error; | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Holds the translation from system network socket options to 3DS network socket options | ||
| 160 | /// Note: -1 = No effect/unavailable | ||
| 161 | static const std::unordered_map<int, int> sockopt_map = {{ | ||
| 162 | {0x0004, SO_REUSEADDR}, | ||
| 163 | {0x0080, -1}, | ||
| 164 | {0x0100, -1}, | ||
| 165 | {0x1001, SO_SNDBUF}, | ||
| 166 | {0x1002, SO_RCVBUF}, | ||
| 167 | {0x1003, -1}, | ||
| 168 | #ifdef _WIN32 | ||
| 169 | /// Unsupported in WinSock2 | ||
| 170 | {0x1004, -1}, | ||
| 171 | #else | ||
| 172 | {0x1004, SO_RCVLOWAT}, | ||
| 173 | #endif | ||
| 174 | {0x1008, SO_TYPE}, | ||
| 175 | {0x1009, SO_ERROR}, | ||
| 176 | }}; | ||
| 177 | |||
| 178 | /// Converts a socket option from 3ds-specific to platform-specific | ||
| 179 | static int TranslateSockOpt(int console_opt_name) { | ||
| 180 | auto found = sockopt_map.find(console_opt_name); | ||
| 181 | if (found != sockopt_map.end()) { | ||
| 182 | return found->second; | ||
| 183 | } | ||
| 184 | return console_opt_name; | ||
| 185 | } | ||
| 186 | |||
| 187 | /// Holds information about a particular socket | ||
| 188 | struct SocketHolder { | ||
| 189 | u32 socket_fd; ///< The socket descriptor | ||
| 190 | bool blocking; ///< Whether the socket is blocking or not, it is only read on Windows. | ||
| 191 | }; | ||
| 192 | |||
| 193 | /// Structure to represent the 3ds' pollfd structure, which is different than most implementations | ||
| 194 | struct CTRPollFD { | ||
| 195 | u32 fd; ///< Socket handle | ||
| 196 | |||
| 197 | union Events { | ||
| 198 | u32 hex; ///< The complete value formed by the flags | ||
| 199 | BitField<0, 1, u32> pollin; | ||
| 200 | BitField<1, 1, u32> pollpri; | ||
| 201 | BitField<2, 1, u32> pollhup; | ||
| 202 | BitField<3, 1, u32> pollerr; | ||
| 203 | BitField<4, 1, u32> pollout; | ||
| 204 | BitField<5, 1, u32> pollnval; | ||
| 205 | |||
| 206 | Events& operator=(const Events& other) { | ||
| 207 | hex = other.hex; | ||
| 208 | return *this; | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Translates the resulting events of a Poll operation from platform-specific to 3ds | ||
| 212 | /// specific | ||
| 213 | static Events TranslateTo3DS(u32 input_event) { | ||
| 214 | Events ev = {}; | ||
| 215 | if (input_event & POLLIN) | ||
| 216 | ev.pollin.Assign(1); | ||
| 217 | if (input_event & POLLPRI) | ||
| 218 | ev.pollpri.Assign(1); | ||
| 219 | if (input_event & POLLHUP) | ||
| 220 | ev.pollhup.Assign(1); | ||
| 221 | if (input_event & POLLERR) | ||
| 222 | ev.pollerr.Assign(1); | ||
| 223 | if (input_event & POLLOUT) | ||
| 224 | ev.pollout.Assign(1); | ||
| 225 | if (input_event & POLLNVAL) | ||
| 226 | ev.pollnval.Assign(1); | ||
| 227 | return ev; | ||
| 228 | } | ||
| 229 | |||
| 230 | /// Translates the resulting events of a Poll operation from 3ds specific to platform | ||
| 231 | /// specific | ||
| 232 | static u32 TranslateToPlatform(Events input_event) { | ||
| 233 | u32 ret = 0; | ||
| 234 | if (input_event.pollin) | ||
| 235 | ret |= POLLIN; | ||
| 236 | if (input_event.pollpri) | ||
| 237 | ret |= POLLPRI; | ||
| 238 | if (input_event.pollhup) | ||
| 239 | ret |= POLLHUP; | ||
| 240 | if (input_event.pollerr) | ||
| 241 | ret |= POLLERR; | ||
| 242 | if (input_event.pollout) | ||
| 243 | ret |= POLLOUT; | ||
| 244 | if (input_event.pollnval) | ||
| 245 | ret |= POLLNVAL; | ||
| 246 | return ret; | ||
| 247 | } | ||
| 248 | }; | ||
| 249 | Events events; ///< Events to poll for (input) | ||
| 250 | Events revents; ///< Events received (output) | ||
| 251 | |||
| 252 | /// Converts a platform-specific pollfd to a 3ds specific structure | ||
| 253 | static CTRPollFD FromPlatform(pollfd const& fd) { | ||
| 254 | CTRPollFD result; | ||
| 255 | result.events.hex = Events::TranslateTo3DS(fd.events).hex; | ||
| 256 | result.revents.hex = Events::TranslateTo3DS(fd.revents).hex; | ||
| 257 | result.fd = static_cast<u32>(fd.fd); | ||
| 258 | return result; | ||
| 259 | } | ||
| 260 | |||
| 261 | /// Converts a 3ds specific pollfd to a platform-specific structure | ||
| 262 | static pollfd ToPlatform(CTRPollFD const& fd) { | ||
| 263 | pollfd result; | ||
| 264 | result.events = Events::TranslateToPlatform(fd.events); | ||
| 265 | result.revents = Events::TranslateToPlatform(fd.revents); | ||
| 266 | result.fd = fd.fd; | ||
| 267 | return result; | ||
| 268 | } | ||
| 269 | }; | ||
| 270 | |||
| 271 | /// Union to represent the 3ds' sockaddr structure | ||
| 272 | union CTRSockAddr { | ||
| 273 | /// Structure to represent a raw sockaddr | ||
| 274 | struct { | ||
| 275 | u8 len; ///< The length of the entire structure, only the set fields count | ||
| 276 | u8 sa_family; ///< The address family of the sockaddr | ||
| 277 | u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family | ||
| 278 | } raw; | ||
| 279 | |||
| 280 | /// Structure to represent the 3ds' sockaddr_in structure | ||
| 281 | struct CTRSockAddrIn { | ||
| 282 | u8 len; ///< The length of the entire structure | ||
| 283 | u8 sin_family; ///< The address family of the sockaddr_in | ||
| 284 | u16 sin_port; ///< The port associated with this sockaddr_in | ||
| 285 | u32 sin_addr; ///< The actual address of the sockaddr_in | ||
| 286 | } in; | ||
| 287 | |||
| 288 | /// Convert a 3DS CTRSockAddr to a platform-specific sockaddr | ||
| 289 | static sockaddr ToPlatform(CTRSockAddr const& ctr_addr) { | ||
| 290 | sockaddr result; | ||
| 291 | result.sa_family = ctr_addr.raw.sa_family; | ||
| 292 | memset(result.sa_data, 0, sizeof(result.sa_data)); | ||
| 293 | |||
| 294 | // We can not guarantee ABI compatibility between platforms so we copy the fields manually | ||
| 295 | switch (result.sa_family) { | ||
| 296 | case AF_INET: { | ||
| 297 | sockaddr_in* result_in = reinterpret_cast<sockaddr_in*>(&result); | ||
| 298 | result_in->sin_port = ctr_addr.in.sin_port; | ||
| 299 | result_in->sin_addr.s_addr = ctr_addr.in.sin_addr; | ||
| 300 | memset(result_in->sin_zero, 0, sizeof(result_in->sin_zero)); | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | default: | ||
| 304 | ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform"); | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | return result; | ||
| 308 | } | ||
| 309 | |||
| 310 | /// Convert a platform-specific sockaddr to a 3DS CTRSockAddr | ||
| 311 | static CTRSockAddr FromPlatform(sockaddr const& addr) { | ||
| 312 | CTRSockAddr result; | ||
| 313 | result.raw.sa_family = static_cast<u8>(addr.sa_family); | ||
| 314 | // We can not guarantee ABI compatibility between platforms so we copy the fields manually | ||
| 315 | switch (result.raw.sa_family) { | ||
| 316 | case AF_INET: { | ||
| 317 | sockaddr_in const* addr_in = reinterpret_cast<sockaddr_in const*>(&addr); | ||
| 318 | result.raw.len = sizeof(CTRSockAddrIn); | ||
| 319 | result.in.sin_port = addr_in->sin_port; | ||
| 320 | result.in.sin_addr = addr_in->sin_addr.s_addr; | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | default: | ||
| 324 | ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform"); | ||
| 325 | break; | ||
| 326 | } | ||
| 327 | return result; | ||
| 328 | } | ||
| 329 | }; | ||
| 330 | |||
| 331 | /// Holds info about the currently open sockets | ||
| 332 | static std::unordered_map<u32, SocketHolder> open_sockets; | ||
| 333 | |||
| 334 | /// Close all open sockets | ||
| 335 | static void CleanupSockets() { | ||
| 336 | for (auto sock : open_sockets) | ||
| 337 | closesocket(sock.second.socket_fd); | ||
| 338 | open_sockets.clear(); | ||
| 339 | } | ||
| 340 | |||
| 341 | static void Socket(Interface* self) { | ||
| 342 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 343 | u32 domain = cmd_buffer[1]; // Address family | ||
| 344 | u32 type = cmd_buffer[2]; | ||
| 345 | u32 protocol = cmd_buffer[3]; | ||
| 346 | |||
| 347 | // Only 0 is allowed according to 3dbrew, using 0 will let the OS decide which protocol to use | ||
| 348 | if (protocol != 0) { | ||
| 349 | cmd_buffer[1] = | ||
| 350 | UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code | ||
| 351 | return; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (domain != AF_INET) { | ||
| 355 | cmd_buffer[1] = | ||
| 356 | UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code | ||
| 357 | return; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (type != SOCK_DGRAM && type != SOCK_STREAM) { | ||
| 361 | cmd_buffer[1] = | ||
| 362 | UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code | ||
| 363 | return; | ||
| 364 | } | ||
| 365 | |||
| 366 | u32 ret = static_cast<u32>(::socket(domain, type, protocol)); | ||
| 367 | |||
| 368 | if ((s32)ret != SOCKET_ERROR_VALUE) | ||
| 369 | open_sockets[ret] = {ret, true}; | ||
| 370 | |||
| 371 | int result = 0; | ||
| 372 | if ((s32)ret == SOCKET_ERROR_VALUE) | ||
| 373 | ret = TranslateError(GET_ERRNO); | ||
| 374 | |||
| 375 | cmd_buffer[0] = IPC::MakeHeader(2, 2, 0); | ||
| 376 | cmd_buffer[1] = result; | ||
| 377 | cmd_buffer[2] = ret; | ||
| 378 | } | ||
| 379 | |||
| 380 | static void Bind(Interface* self) { | ||
| 381 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 382 | u32 socket_handle = cmd_buffer[1]; | ||
| 383 | u32 len = cmd_buffer[2]; | ||
| 384 | |||
| 385 | // Virtual address of the sock_addr structure | ||
| 386 | VAddr sock_addr_addr = cmd_buffer[6]; | ||
| 387 | if (!Memory::IsValidVirtualAddress(sock_addr_addr)) { | ||
| 388 | cmd_buffer[1] = -1; // TODO(Subv): Correct code | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | |||
| 392 | CTRSockAddr ctr_sock_addr; | ||
| 393 | Memory::ReadBlock(sock_addr_addr, reinterpret_cast<u8*>(&ctr_sock_addr), sizeof(CTRSockAddr)); | ||
| 394 | |||
| 395 | sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr); | ||
| 396 | |||
| 397 | int ret = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); | ||
| 398 | |||
| 399 | int result = 0; | ||
| 400 | if (ret != 0) | ||
| 401 | ret = TranslateError(GET_ERRNO); | ||
| 402 | |||
| 403 | cmd_buffer[0] = IPC::MakeHeader(5, 2, 0); | ||
| 404 | cmd_buffer[1] = result; | ||
| 405 | cmd_buffer[2] = ret; | ||
| 406 | } | ||
| 407 | |||
| 408 | static void Fcntl(Interface* self) { | ||
| 409 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 410 | u32 socket_handle = cmd_buffer[1]; | ||
| 411 | u32 ctr_cmd = cmd_buffer[2]; | ||
| 412 | u32 ctr_arg = cmd_buffer[3]; | ||
| 413 | |||
| 414 | int result = 0; | ||
| 415 | u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) | ||
| 416 | SCOPE_EXIT({ | ||
| 417 | cmd_buffer[1] = result; | ||
| 418 | cmd_buffer[2] = posix_ret; | ||
| 419 | }); | ||
| 420 | |||
| 421 | if (ctr_cmd == 3) { // F_GETFL | ||
| 422 | #ifdef _WIN32 | ||
| 423 | posix_ret = 0; | ||
| 424 | auto iter = open_sockets.find(socket_handle); | ||
| 425 | if (iter != open_sockets.end() && iter->second.blocking == false) | ||
| 426 | posix_ret |= 4; // O_NONBLOCK | ||
| 427 | #else | ||
| 428 | int ret = ::fcntl(socket_handle, F_GETFL, 0); | ||
| 429 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 430 | posix_ret = TranslateError(GET_ERRNO); | ||
| 431 | return; | ||
| 432 | } | ||
| 433 | posix_ret = 0; | ||
| 434 | if (ret & O_NONBLOCK) | ||
| 435 | posix_ret |= 4; // O_NONBLOCK | ||
| 436 | #endif | ||
| 437 | } else if (ctr_cmd == 4) { // F_SETFL | ||
| 438 | #ifdef _WIN32 | ||
| 439 | unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; | ||
| 440 | int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); | ||
| 441 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 442 | posix_ret = TranslateError(GET_ERRNO); | ||
| 443 | return; | ||
| 444 | } | ||
| 445 | auto iter = open_sockets.find(socket_handle); | ||
| 446 | if (iter != open_sockets.end()) | ||
| 447 | iter->second.blocking = (tmp == 0); | ||
| 448 | #else | ||
| 449 | int flags = ::fcntl(socket_handle, F_GETFL, 0); | ||
| 450 | if (flags == SOCKET_ERROR_VALUE) { | ||
| 451 | posix_ret = TranslateError(GET_ERRNO); | ||
| 452 | return; | ||
| 453 | } | ||
| 454 | |||
| 455 | flags &= ~O_NONBLOCK; | ||
| 456 | if (ctr_arg & 4) // O_NONBLOCK | ||
| 457 | flags |= O_NONBLOCK; | ||
| 458 | |||
| 459 | int ret = ::fcntl(socket_handle, F_SETFL, flags); | ||
| 460 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 461 | posix_ret = TranslateError(GET_ERRNO); | ||
| 462 | return; | ||
| 463 | } | ||
| 464 | #endif | ||
| 465 | } else { | ||
| 466 | LOG_ERROR(Service_SOC, "Unsupported command (%d) in fcntl call", ctr_cmd); | ||
| 467 | posix_ret = TranslateError(EINVAL); // TODO: Find the correct error | ||
| 468 | return; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | static void Listen(Interface* self) { | ||
| 473 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 474 | u32 socket_handle = cmd_buffer[1]; | ||
| 475 | u32 backlog = cmd_buffer[2]; | ||
| 476 | |||
| 477 | int ret = ::listen(socket_handle, backlog); | ||
| 478 | int result = 0; | ||
| 479 | if (ret != 0) | ||
| 480 | ret = TranslateError(GET_ERRNO); | ||
| 481 | |||
| 482 | cmd_buffer[0] = IPC::MakeHeader(3, 2, 0); | ||
| 483 | cmd_buffer[1] = result; | ||
| 484 | cmd_buffer[2] = ret; | ||
| 485 | } | ||
| 486 | |||
| 487 | static void Accept(Interface* self) { | ||
| 488 | // TODO(Subv): Calling this function on a blocking socket will block the emu thread, | ||
| 489 | // preventing graceful shutdown when closing the emulator, this can be fixed by always | ||
| 490 | // performing nonblocking operations and spinlock until the data is available | ||
| 491 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 492 | u32 socket_handle = cmd_buffer[1]; | ||
| 493 | socklen_t max_addr_len = static_cast<socklen_t>(cmd_buffer[2]); | ||
| 494 | sockaddr addr; | ||
| 495 | socklen_t addr_len = sizeof(addr); | ||
| 496 | u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); | ||
| 497 | |||
| 498 | if ((s32)ret != SOCKET_ERROR_VALUE) | ||
| 499 | open_sockets[ret] = {ret, true}; | ||
| 500 | |||
| 501 | int result = 0; | ||
| 502 | if ((s32)ret == SOCKET_ERROR_VALUE) { | ||
| 503 | ret = TranslateError(GET_ERRNO); | ||
| 504 | } else { | ||
| 505 | CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr); | ||
| 506 | Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr)); | ||
| 507 | } | ||
| 508 | |||
| 509 | cmd_buffer[0] = IPC::MakeHeader(4, 2, 2); | ||
| 510 | cmd_buffer[1] = result; | ||
| 511 | cmd_buffer[2] = ret; | ||
| 512 | cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0); | ||
| 513 | } | ||
| 514 | |||
| 515 | static void GetHostId(Interface* self) { | ||
| 516 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 517 | |||
| 518 | char name[128]; | ||
| 519 | gethostname(name, sizeof(name)); | ||
| 520 | addrinfo hints = {}; | ||
| 521 | addrinfo* res; | ||
| 522 | |||
| 523 | hints.ai_family = AF_INET; | ||
| 524 | getaddrinfo(name, nullptr, &hints, &res); | ||
| 525 | sockaddr_in* sock_addr = reinterpret_cast<sockaddr_in*>(res->ai_addr); | ||
| 526 | in_addr* addr = &sock_addr->sin_addr; | ||
| 527 | |||
| 528 | cmd_buffer[2] = addr->s_addr; | ||
| 529 | cmd_buffer[1] = 0; | ||
| 530 | freeaddrinfo(res); | ||
| 531 | } | ||
| 532 | |||
| 533 | static void Close(Interface* self) { | ||
| 534 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 535 | u32 socket_handle = cmd_buffer[1]; | ||
| 536 | |||
| 537 | int ret = 0; | ||
| 538 | open_sockets.erase(socket_handle); | ||
| 539 | |||
| 540 | ret = closesocket(socket_handle); | ||
| 541 | |||
| 542 | int result = 0; | ||
| 543 | if (ret != 0) | ||
| 544 | ret = TranslateError(GET_ERRNO); | ||
| 545 | |||
| 546 | cmd_buffer[2] = ret; | ||
| 547 | cmd_buffer[1] = result; | ||
| 548 | } | ||
| 549 | |||
| 550 | static void SendTo(Interface* self) { | ||
| 551 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 552 | u32 socket_handle = cmd_buffer[1]; | ||
| 553 | u32 len = cmd_buffer[2]; | ||
| 554 | u32 flags = cmd_buffer[3]; | ||
| 555 | u32 addr_len = cmd_buffer[4]; | ||
| 556 | |||
| 557 | VAddr input_buff_address = cmd_buffer[8]; | ||
| 558 | if (!Memory::IsValidVirtualAddress(input_buff_address)) { | ||
| 559 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 560 | return; | ||
| 561 | } | ||
| 562 | |||
| 563 | // Memory address of the dest_addr structure | ||
| 564 | VAddr dest_addr_addr = cmd_buffer[10]; | ||
| 565 | if (!Memory::IsValidVirtualAddress(dest_addr_addr)) { | ||
| 566 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 567 | return; | ||
| 568 | } | ||
| 569 | |||
| 570 | std::vector<u8> input_buff(len); | ||
| 571 | Memory::ReadBlock(input_buff_address, input_buff.data(), input_buff.size()); | ||
| 572 | |||
| 573 | CTRSockAddr ctr_dest_addr; | ||
| 574 | Memory::ReadBlock(dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); | ||
| 575 | |||
| 576 | int ret = -1; | ||
| 577 | if (addr_len > 0) { | ||
| 578 | sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr); | ||
| 579 | ret = ::sendto(socket_handle, reinterpret_cast<const char*>(input_buff.data()), len, flags, | ||
| 580 | &dest_addr, sizeof(dest_addr)); | ||
| 581 | } else { | ||
| 582 | ret = ::sendto(socket_handle, reinterpret_cast<const char*>(input_buff.data()), len, flags, | ||
| 583 | nullptr, 0); | ||
| 584 | } | ||
| 585 | |||
| 586 | int result = 0; | ||
| 587 | if (ret == SOCKET_ERROR_VALUE) | ||
| 588 | ret = TranslateError(GET_ERRNO); | ||
| 589 | |||
| 590 | cmd_buffer[2] = ret; | ||
| 591 | cmd_buffer[1] = result; | ||
| 592 | } | ||
| 593 | |||
| 594 | static void RecvFrom(Interface* self) { | ||
| 595 | // TODO(Subv): Calling this function on a blocking socket will block the emu thread, | ||
| 596 | // preventing graceful shutdown when closing the emulator, this can be fixed by always | ||
| 597 | // performing nonblocking operations and spinlock until the data is available | ||
| 598 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 599 | u32 socket_handle = cmd_buffer[1]; | ||
| 600 | u32 len = cmd_buffer[2]; | ||
| 601 | u32 flags = cmd_buffer[3]; | ||
| 602 | |||
| 603 | struct { | ||
| 604 | u32 output_buffer_descriptor; | ||
| 605 | u32 output_buffer_addr; | ||
| 606 | u32 address_buffer_descriptor; | ||
| 607 | u32 output_src_address_buffer; | ||
| 608 | } buffer_parameters; | ||
| 609 | |||
| 610 | std::memcpy(&buffer_parameters, &cmd_buffer[64], sizeof(buffer_parameters)); | ||
| 611 | |||
| 612 | if (!Memory::IsValidVirtualAddress(buffer_parameters.output_buffer_addr)) { | ||
| 613 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 614 | return; | ||
| 615 | } | ||
| 616 | |||
| 617 | if (!Memory::IsValidVirtualAddress(buffer_parameters.output_src_address_buffer)) { | ||
| 618 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 619 | return; | ||
| 620 | } | ||
| 621 | |||
| 622 | std::vector<u8> output_buff(len); | ||
| 623 | sockaddr src_addr; | ||
| 624 | socklen_t src_addr_len = sizeof(src_addr); | ||
| 625 | int ret = ::recvfrom(socket_handle, reinterpret_cast<char*>(output_buff.data()), len, flags, | ||
| 626 | &src_addr, &src_addr_len); | ||
| 627 | |||
| 628 | if (ret >= 0 && buffer_parameters.output_src_address_buffer != 0 && src_addr_len > 0) { | ||
| 629 | CTRSockAddr ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); | ||
| 630 | Memory::WriteBlock(buffer_parameters.output_src_address_buffer, &ctr_src_addr, | ||
| 631 | sizeof(ctr_src_addr)); | ||
| 632 | } | ||
| 633 | |||
| 634 | int result = 0; | ||
| 635 | int total_received = ret; | ||
| 636 | if (ret == SOCKET_ERROR_VALUE) { | ||
| 637 | ret = TranslateError(GET_ERRNO); | ||
| 638 | total_received = 0; | ||
| 639 | } else { | ||
| 640 | // Write only the data we received to avoid overwriting parts of the buffer with zeros | ||
| 641 | Memory::WriteBlock(buffer_parameters.output_buffer_addr, output_buff.data(), | ||
| 642 | total_received); | ||
| 643 | } | ||
| 644 | |||
| 645 | cmd_buffer[1] = result; | ||
| 646 | cmd_buffer[2] = ret; | ||
| 647 | cmd_buffer[3] = total_received; | ||
| 648 | } | ||
| 649 | |||
| 650 | static void Poll(Interface* self) { | ||
| 651 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 652 | u32 nfds = cmd_buffer[1]; | ||
| 653 | int timeout = cmd_buffer[2]; | ||
| 654 | |||
| 655 | VAddr input_fds_addr = cmd_buffer[6]; | ||
| 656 | VAddr output_fds_addr = cmd_buffer[0x104 >> 2]; | ||
| 657 | if (!Memory::IsValidVirtualAddress(input_fds_addr) || | ||
| 658 | !Memory::IsValidVirtualAddress(output_fds_addr)) { | ||
| 659 | cmd_buffer[1] = -1; // TODO(Subv): Find correct error code. | ||
| 660 | return; | ||
| 661 | } | ||
| 662 | |||
| 663 | std::vector<CTRPollFD> ctr_fds(nfds); | ||
| 664 | Memory::ReadBlock(input_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD)); | ||
| 665 | |||
| 666 | // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different | ||
| 667 | // sizes) | ||
| 668 | // so we have to copy the data | ||
| 669 | std::vector<pollfd> platform_pollfd(nfds); | ||
| 670 | std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform); | ||
| 671 | |||
| 672 | int ret = ::poll(platform_pollfd.data(), nfds, timeout); | ||
| 673 | |||
| 674 | // Now update the output pollfd structure | ||
| 675 | std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), | ||
| 676 | CTRPollFD::FromPlatform); | ||
| 677 | |||
| 678 | Memory::WriteBlock(output_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD)); | ||
| 679 | |||
| 680 | int result = 0; | ||
| 681 | if (ret == SOCKET_ERROR_VALUE) | ||
| 682 | ret = TranslateError(GET_ERRNO); | ||
| 683 | |||
| 684 | cmd_buffer[1] = result; | ||
| 685 | cmd_buffer[2] = ret; | ||
| 686 | } | ||
| 687 | |||
| 688 | static void GetSockName(Interface* self) { | ||
| 689 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 690 | u32 socket_handle = cmd_buffer[1]; | ||
| 691 | |||
| 692 | // Memory address of the ctr_dest_addr structure | ||
| 693 | VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2]; | ||
| 694 | |||
| 695 | sockaddr dest_addr; | ||
| 696 | socklen_t dest_addr_len = sizeof(dest_addr); | ||
| 697 | int ret = ::getsockname(socket_handle, &dest_addr, &dest_addr_len); | ||
| 698 | |||
| 699 | if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) { | ||
| 700 | CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); | ||
| 701 | Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); | ||
| 702 | } else { | ||
| 703 | cmd_buffer[1] = -1; // TODO(Subv): Verify error | ||
| 704 | return; | ||
| 705 | } | ||
| 706 | |||
| 707 | int result = 0; | ||
| 708 | if (ret != 0) | ||
| 709 | ret = TranslateError(GET_ERRNO); | ||
| 710 | |||
| 711 | cmd_buffer[2] = ret; | ||
| 712 | cmd_buffer[1] = result; | ||
| 713 | } | ||
| 714 | |||
| 715 | static void Shutdown(Interface* self) { | ||
| 716 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 717 | u32 socket_handle = cmd_buffer[1]; | ||
| 718 | int how = cmd_buffer[2]; | ||
| 719 | |||
| 720 | int ret = ::shutdown(socket_handle, how); | ||
| 721 | int result = 0; | ||
| 722 | if (ret != 0) | ||
| 723 | ret = TranslateError(GET_ERRNO); | ||
| 724 | cmd_buffer[2] = ret; | ||
| 725 | cmd_buffer[1] = result; | ||
| 726 | } | ||
| 727 | |||
| 728 | static void GetPeerName(Interface* self) { | ||
| 729 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 730 | u32 socket_handle = cmd_buffer[1]; | ||
| 731 | |||
| 732 | // Memory address of the ctr_dest_addr structure | ||
| 733 | VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2]; | ||
| 734 | |||
| 735 | sockaddr dest_addr; | ||
| 736 | socklen_t dest_addr_len = sizeof(dest_addr); | ||
| 737 | int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); | ||
| 738 | |||
| 739 | if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) { | ||
| 740 | CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); | ||
| 741 | Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); | ||
| 742 | } else { | ||
| 743 | cmd_buffer[1] = -1; | ||
| 744 | return; | ||
| 745 | } | ||
| 746 | |||
| 747 | int result = 0; | ||
| 748 | if (ret != 0) | ||
| 749 | ret = TranslateError(GET_ERRNO); | ||
| 750 | |||
| 751 | cmd_buffer[2] = ret; | ||
| 752 | cmd_buffer[1] = result; | ||
| 753 | } | ||
| 754 | |||
| 755 | static void Connect(Interface* self) { | ||
| 756 | // TODO(Subv): Calling this function on a blocking socket will block the emu thread, | ||
| 757 | // preventing graceful shutdown when closing the emulator, this can be fixed by always | ||
| 758 | // performing nonblocking operations and spinlock until the data is available | ||
| 759 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 760 | u32 socket_handle = cmd_buffer[1]; | ||
| 761 | |||
| 762 | // Memory address of the ctr_input_addr structure | ||
| 763 | VAddr ctr_input_addr_addr = cmd_buffer[6]; | ||
| 764 | if (!Memory::IsValidVirtualAddress(ctr_input_addr_addr)) { | ||
| 765 | cmd_buffer[1] = -1; // TODO(Subv): Verify error | ||
| 766 | return; | ||
| 767 | } | ||
| 768 | |||
| 769 | CTRSockAddr ctr_input_addr; | ||
| 770 | Memory::ReadBlock(ctr_input_addr_addr, &ctr_input_addr, sizeof(ctr_input_addr)); | ||
| 771 | |||
| 772 | sockaddr input_addr = CTRSockAddr::ToPlatform(ctr_input_addr); | ||
| 773 | int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr)); | ||
| 774 | int result = 0; | ||
| 775 | if (ret != 0) | ||
| 776 | ret = TranslateError(GET_ERRNO); | ||
| 777 | |||
| 778 | cmd_buffer[0] = IPC::MakeHeader(6, 2, 0); | ||
| 779 | cmd_buffer[1] = result; | ||
| 780 | cmd_buffer[2] = ret; | ||
| 781 | } | ||
| 782 | |||
| 783 | static void InitializeSockets(Interface* self) { | ||
| 784 | // TODO(Subv): Implement | ||
| 785 | #ifdef _WIN32 | ||
| 786 | WSADATA data; | ||
| 787 | WSAStartup(MAKEWORD(2, 2), &data); | ||
| 788 | #endif | ||
| 789 | |||
| 790 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 791 | cmd_buffer[0] = IPC::MakeHeader(1, 1, 0); | ||
| 792 | cmd_buffer[1] = RESULT_SUCCESS.raw; | ||
| 793 | } | ||
| 794 | |||
| 795 | static void ShutdownSockets(Interface* self) { | ||
| 796 | // TODO(Subv): Implement | ||
| 797 | CleanupSockets(); | ||
| 798 | |||
| 799 | #ifdef _WIN32 | ||
| 800 | WSACleanup(); | ||
| 801 | #endif | ||
| 802 | |||
| 803 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 804 | cmd_buffer[1] = 0; | ||
| 805 | } | ||
| 806 | |||
| 807 | static void GetSockOpt(Interface* self) { | ||
| 808 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 809 | u32 socket_handle = cmd_buffer[1]; | ||
| 810 | u32 level = cmd_buffer[2]; | ||
| 811 | int optname = TranslateSockOpt(cmd_buffer[3]); | ||
| 812 | socklen_t optlen = (socklen_t)cmd_buffer[4]; | ||
| 813 | |||
| 814 | int ret = 0; | ||
| 815 | int err = 0; | ||
| 816 | |||
| 817 | if (optname < 0) { | ||
| 818 | #ifdef _WIN32 | ||
| 819 | err = WSAEINVAL; | ||
| 820 | #else | ||
| 821 | err = EINVAL; | ||
| 822 | #endif | ||
| 823 | } else { | ||
| 824 | // 0x100 = static buffer offset (bytes) | ||
| 825 | // + 0x4 = 2nd pointer (u32) position | ||
| 826 | // >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*) | ||
| 827 | char* optval = reinterpret_cast<char*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); | ||
| 828 | |||
| 829 | err = ::getsockopt(socket_handle, level, optname, optval, &optlen); | ||
| 830 | if (err == SOCKET_ERROR_VALUE) { | ||
| 831 | err = TranslateError(GET_ERRNO); | ||
| 832 | } | ||
| 833 | } | ||
| 834 | |||
| 835 | cmd_buffer[0] = IPC::MakeHeader(0x11, 4, 2); | ||
| 836 | cmd_buffer[1] = ret; | ||
| 837 | cmd_buffer[2] = err; | ||
| 838 | cmd_buffer[3] = optlen; | ||
| 839 | } | ||
| 840 | |||
| 841 | static void SetSockOpt(Interface* self) { | ||
| 842 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 843 | u32 socket_handle = cmd_buffer[1]; | ||
| 844 | u32 level = cmd_buffer[2]; | ||
| 845 | int optname = TranslateSockOpt(cmd_buffer[3]); | ||
| 846 | |||
| 847 | int ret = 0; | ||
| 848 | int err = 0; | ||
| 849 | |||
| 850 | if (optname < 0) { | ||
| 851 | #ifdef _WIN32 | ||
| 852 | err = WSAEINVAL; | ||
| 853 | #else | ||
| 854 | err = EINVAL; | ||
| 855 | #endif | ||
| 856 | } else { | ||
| 857 | socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]); | ||
| 858 | const char* optval = reinterpret_cast<const char*>(Memory::GetPointer(cmd_buffer[8])); | ||
| 859 | |||
| 860 | err = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen)); | ||
| 861 | if (err == SOCKET_ERROR_VALUE) { | ||
| 862 | err = TranslateError(GET_ERRNO); | ||
| 863 | } | ||
| 864 | } | ||
| 865 | |||
| 866 | cmd_buffer[0] = IPC::MakeHeader(0x12, 4, 4); | ||
| 867 | cmd_buffer[1] = ret; | ||
| 868 | cmd_buffer[2] = err; | ||
| 869 | } | ||
| 870 | |||
| 871 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 872 | {0x00010044, InitializeSockets, "InitializeSockets"}, | ||
| 873 | {0x000200C2, Socket, "Socket"}, | ||
| 874 | {0x00030082, Listen, "Listen"}, | ||
| 875 | {0x00040082, Accept, "Accept"}, | ||
| 876 | {0x00050084, Bind, "Bind"}, | ||
| 877 | {0x00060084, Connect, "Connect"}, | ||
| 878 | {0x00070104, nullptr, "recvfrom_other"}, | ||
| 879 | {0x00080102, RecvFrom, "RecvFrom"}, | ||
| 880 | {0x00090106, nullptr, "sendto_other"}, | ||
| 881 | {0x000A0106, SendTo, "SendTo"}, | ||
| 882 | {0x000B0042, Close, "Close"}, | ||
| 883 | {0x000C0082, Shutdown, "Shutdown"}, | ||
| 884 | {0x000D0082, nullptr, "GetHostByName"}, | ||
| 885 | {0x000E00C2, nullptr, "GetHostByAddr"}, | ||
| 886 | {0x000F0106, nullptr, "GetAddrInfo"}, | ||
| 887 | {0x00100102, nullptr, "GetNameInfo"}, | ||
| 888 | {0x00110102, GetSockOpt, "GetSockOpt"}, | ||
| 889 | {0x00120104, SetSockOpt, "SetSockOpt"}, | ||
| 890 | {0x001300C2, Fcntl, "Fcntl"}, | ||
| 891 | {0x00140084, Poll, "Poll"}, | ||
| 892 | {0x00150042, nullptr, "SockAtMark"}, | ||
| 893 | {0x00160000, GetHostId, "GetHostId"}, | ||
| 894 | {0x00170082, GetSockName, "GetSockName"}, | ||
| 895 | {0x00180082, GetPeerName, "GetPeerName"}, | ||
| 896 | {0x00190000, ShutdownSockets, "ShutdownSockets"}, | ||
| 897 | {0x001A00C0, nullptr, "GetNetworkOpt"}, | ||
| 898 | {0x001B0040, nullptr, "ICMPSocket"}, | ||
| 899 | {0x001C0104, nullptr, "ICMPPing"}, | ||
| 900 | {0x001D0040, nullptr, "ICMPCancel"}, | ||
| 901 | {0x001E0040, nullptr, "ICMPClose"}, | ||
| 902 | {0x001F0040, nullptr, "GetResolverInfo"}, | ||
| 903 | {0x00210002, nullptr, "CloseSockets"}, | ||
| 904 | {0x00230040, nullptr, "AddGlobalSocket"}, | ||
| 905 | }; | ||
| 906 | |||
| 907 | SOC_U::SOC_U() { | ||
| 908 | Register(FunctionTable); | ||
| 909 | } | ||
| 910 | |||
| 911 | SOC_U::~SOC_U() { | ||
| 912 | CleanupSockets(); | ||
| 913 | #ifdef _WIN32 | ||
| 914 | WSACleanup(); | ||
| 915 | #endif | ||
| 916 | } | ||
| 917 | |||
| 918 | } // namespace SOC | ||
| 919 | } // namespace Service | ||
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h deleted file mode 100644 index 5f829fc1c..000000000 --- a/src/core/hle/service/soc_u.h +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace SOC { | ||
| 12 | |||
| 13 | class SOC_U final : public Interface { | ||
| 14 | public: | ||
| 15 | SOC_U(); | ||
| 16 | ~SOC_U(); | ||
| 17 | |||
| 18 | std::string GetPortName() const override { | ||
| 19 | return "soc:U"; | ||
| 20 | } | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace SOC | ||
| 24 | } // namespace Service | ||
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp deleted file mode 100644 index 300acca75..000000000 --- a/src/core/hle/service/ssl_c.cpp +++ /dev/null | |||
| @@ -1,92 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <random> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/ipc.h" | ||
| 8 | #include "core/hle/service/ssl_c.h" | ||
| 9 | #include "core/memory.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace SSL { | ||
| 13 | |||
| 14 | // TODO: Implement a proper CSPRNG in the future when actual security is needed | ||
| 15 | static std::mt19937 rand_gen; | ||
| 16 | |||
| 17 | static void Initialize(Interface* self) { | ||
| 18 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 19 | |||
| 20 | // Seed random number generator when the SSL service is initialized | ||
| 21 | std::random_device rand_device; | ||
| 22 | rand_gen.seed(rand_device()); | ||
| 23 | |||
| 24 | // Stub, return success | ||
| 25 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 26 | } | ||
| 27 | |||
| 28 | static void GenerateRandomData(Interface* self) { | ||
| 29 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 30 | |||
| 31 | u32 size = cmd_buff[1]; | ||
| 32 | VAddr address = cmd_buff[3]; | ||
| 33 | |||
| 34 | // Fill the output buffer with random data. | ||
| 35 | u32 data = 0; | ||
| 36 | u32 i = 0; | ||
| 37 | while (i < size) { | ||
| 38 | if ((i % 4) == 0) { | ||
| 39 | // The random number generator returns 4 bytes worth of data, so generate new random | ||
| 40 | // data when i == 0 and when i is divisible by 4 | ||
| 41 | data = rand_gen(); | ||
| 42 | } | ||
| 43 | |||
| 44 | if (size > 4) { | ||
| 45 | // Use up the entire 4 bytes of the random data for as long as possible | ||
| 46 | Memory::Write32(address + i, data); | ||
| 47 | i += 4; | ||
| 48 | } else if (size == 2) { | ||
| 49 | Memory::Write16(address + i, static_cast<u16>(data & 0xffff)); | ||
| 50 | i += 2; | ||
| 51 | } else { | ||
| 52 | Memory::Write8(address + i, static_cast<u8>(data & 0xff)); | ||
| 53 | i++; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | // Stub, return success | ||
| 58 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 59 | } | ||
| 60 | |||
| 61 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 62 | {0x00010002, Initialize, "Initialize"}, | ||
| 63 | {0x000200C2, nullptr, "CreateContext"}, | ||
| 64 | {0x00030000, nullptr, "CreateRootCertChain"}, | ||
| 65 | {0x00040040, nullptr, "DestroyRootCertChain"}, | ||
| 66 | {0x00050082, nullptr, "AddTrustedRootCA"}, | ||
| 67 | {0x00060080, nullptr, "RootCertChainAddDefaultCert"}, | ||
| 68 | {0x00070080, nullptr, "RootCertChainRemoveCert"}, | ||
| 69 | {0x000D0084, nullptr, "OpenClientCertContext"}, | ||
| 70 | {0x000E0040, nullptr, "OpenDefaultClientCertContext"}, | ||
| 71 | {0x000F0040, nullptr, "CloseClientCertContext"}, | ||
| 72 | {0x00110042, GenerateRandomData, "GenerateRandomData"}, | ||
| 73 | {0x00120042, nullptr, "InitializeConnectionSession"}, | ||
| 74 | {0x00130040, nullptr, "StartConnection"}, | ||
| 75 | {0x00140040, nullptr, "StartConnectionGetOut"}, | ||
| 76 | {0x00150082, nullptr, "Read"}, | ||
| 77 | {0x00160082, nullptr, "ReadPeek"}, | ||
| 78 | {0x00170082, nullptr, "Write"}, | ||
| 79 | {0x00180080, nullptr, "ContextSetRootCertChain"}, | ||
| 80 | {0x00190080, nullptr, "ContextSetClientCert"}, | ||
| 81 | {0x001B0080, nullptr, "ContextClearOpt"}, | ||
| 82 | {0x001C00C4, nullptr, "ContextGetProtocolCipher"}, | ||
| 83 | {0x001E0040, nullptr, "DestroyContext"}, | ||
| 84 | {0x001F0082, nullptr, "ContextInitSharedmem"}, | ||
| 85 | }; | ||
| 86 | |||
| 87 | SSL_C::SSL_C() { | ||
| 88 | Register(FunctionTable); | ||
| 89 | } | ||
| 90 | |||
| 91 | } // namespace SSL_C | ||
| 92 | } // namespace Service | ||
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h deleted file mode 100644 index fc50a2eb2..000000000 --- a/src/core/hle/service/ssl_c.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace SSL { | ||
| 11 | |||
| 12 | class SSL_C final : public Interface { | ||
| 13 | public: | ||
| 14 | SSL_C(); | ||
| 15 | |||
| 16 | std::string GetPortName() const override { | ||
| 17 | return "ssl:C"; | ||
| 18 | } | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace SSL | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp deleted file mode 100644 index 57172ddd6..000000000 --- a/src/core/hle/service/y2r_u.cpp +++ /dev/null | |||
| @@ -1,787 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/ipc.h" | ||
| 10 | #include "core/hle/ipc_helpers.h" | ||
| 11 | #include "core/hle/kernel/event.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | ||
| 13 | #include "core/hle/service/y2r_u.h" | ||
| 14 | #include "core/hw/y2r.h" | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace Y2R { | ||
| 18 | |||
| 19 | struct ConversionParameters { | ||
| 20 | InputFormat input_format; | ||
| 21 | OutputFormat output_format; | ||
| 22 | Rotation rotation; | ||
| 23 | BlockAlignment block_alignment; | ||
| 24 | u16 input_line_width; | ||
| 25 | u16 input_lines; | ||
| 26 | StandardCoefficient standard_coefficient; | ||
| 27 | u8 padding; | ||
| 28 | u16 alpha; | ||
| 29 | }; | ||
| 30 | static_assert(sizeof(ConversionParameters) == 12, "ConversionParameters struct has incorrect size"); | ||
| 31 | |||
| 32 | static Kernel::SharedPtr<Kernel::Event> completion_event; | ||
| 33 | static ConversionConfiguration conversion; | ||
| 34 | static DitheringWeightParams dithering_weight_params; | ||
| 35 | static u32 temporal_dithering_enabled = 0; | ||
| 36 | static u32 transfer_end_interrupt_enabled = 0; | ||
| 37 | static u32 spacial_dithering_enabled = 0; | ||
| 38 | |||
| 39 | static const CoefficientSet standard_coefficients[4] = { | ||
| 40 | {{0x100, 0x166, 0xB6, 0x58, 0x1C5, -0x166F, 0x10EE, -0x1C5B}}, // ITU_Rec601 | ||
| 41 | {{0x100, 0x193, 0x77, 0x2F, 0x1DB, -0x1933, 0xA7C, -0x1D51}}, // ITU_Rec709 | ||
| 42 | {{0x12A, 0x198, 0xD0, 0x64, 0x204, -0x1BDE, 0x10F2, -0x229B}}, // ITU_Rec601_Scaling | ||
| 43 | {{0x12A, 0x1CA, 0x88, 0x36, 0x21C, -0x1F04, 0x99C, -0x2421}}, // ITU_Rec709_Scaling | ||
| 44 | }; | ||
| 45 | |||
| 46 | ResultCode ConversionConfiguration::SetInputLineWidth(u16 width) { | ||
| 47 | if (width == 0 || width > 1024 || width % 8 != 0) { | ||
| 48 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM, | ||
| 49 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD | ||
| 50 | } | ||
| 51 | |||
| 52 | // Note: The hardware uses the register value 0 to represent a width of 1024, so for a width of | ||
| 53 | // 1024 the `camera` module would set the value 0 here, but we don't need to emulate this | ||
| 54 | // internal detail. | ||
| 55 | this->input_line_width = width; | ||
| 56 | return RESULT_SUCCESS; | ||
| 57 | } | ||
| 58 | |||
| 59 | ResultCode ConversionConfiguration::SetInputLines(u16 lines) { | ||
| 60 | if (lines == 0 || lines > 1024) { | ||
| 61 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM, | ||
| 62 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD | ||
| 63 | } | ||
| 64 | |||
| 65 | // Note: In what appears to be a bug, the `camera` module does not set the hardware register at | ||
| 66 | // all if `lines` is 1024, so the conversion uses the last value that was set. The intention | ||
| 67 | // was probably to set it to 0 like in SetInputLineWidth. | ||
| 68 | if (lines != 1024) { | ||
| 69 | this->input_lines = lines; | ||
| 70 | } | ||
| 71 | return RESULT_SUCCESS; | ||
| 72 | } | ||
| 73 | |||
| 74 | ResultCode ConversionConfiguration::SetStandardCoefficient( | ||
| 75 | StandardCoefficient standard_coefficient) { | ||
| 76 | size_t index = static_cast<size_t>(standard_coefficient); | ||
| 77 | if (index >= ARRAY_SIZE(standard_coefficients)) { | ||
| 78 | return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::CAM, | ||
| 79 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053ED | ||
| 80 | } | ||
| 81 | |||
| 82 | std::memcpy(coefficients.data(), standard_coefficients[index].data(), sizeof(coefficients)); | ||
| 83 | return RESULT_SUCCESS; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void SetInputFormat(Interface* self) { | ||
| 87 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 88 | |||
| 89 | conversion.input_format = static_cast<InputFormat>(cmd_buff[1]); | ||
| 90 | |||
| 91 | cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||
| 92 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 93 | |||
| 94 | LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format); | ||
| 95 | } | ||
| 96 | |||
| 97 | static void GetInputFormat(Interface* self) { | ||
| 98 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 99 | |||
| 100 | cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0); | ||
| 101 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 102 | cmd_buff[2] = static_cast<u32>(conversion.input_format); | ||
| 103 | |||
| 104 | LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void SetOutputFormat(Interface* self) { | ||
| 108 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 109 | |||
| 110 | conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]); | ||
| 111 | |||
| 112 | cmd_buff[0] = IPC::MakeHeader(0x3, 1, 0); | ||
| 113 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 114 | |||
| 115 | LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void GetOutputFormat(Interface* self) { | ||
| 119 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 120 | |||
| 121 | cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0); | ||
| 122 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 123 | cmd_buff[2] = static_cast<u32>(conversion.output_format); | ||
| 124 | |||
| 125 | LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format); | ||
| 126 | } | ||
| 127 | |||
| 128 | static void SetRotation(Interface* self) { | ||
| 129 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 130 | |||
| 131 | conversion.rotation = static_cast<Rotation>(cmd_buff[1]); | ||
| 132 | |||
| 133 | cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0); | ||
| 134 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 135 | |||
| 136 | LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void GetRotation(Interface* self) { | ||
| 140 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 141 | |||
| 142 | cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0); | ||
| 143 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 144 | cmd_buff[2] = static_cast<u32>(conversion.rotation); | ||
| 145 | |||
| 146 | LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation); | ||
| 147 | } | ||
| 148 | |||
| 149 | static void SetBlockAlignment(Interface* self) { | ||
| 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 151 | |||
| 152 | conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]); | ||
| 153 | |||
| 154 | cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0); | ||
| 155 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 156 | |||
| 157 | LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment); | ||
| 158 | } | ||
| 159 | |||
| 160 | static void GetBlockAlignment(Interface* self) { | ||
| 161 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 162 | |||
| 163 | cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0); | ||
| 164 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 165 | cmd_buff[2] = static_cast<u32>(conversion.block_alignment); | ||
| 166 | |||
| 167 | LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment); | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Y2R_U::SetSpacialDithering service function | ||
| 172 | * Inputs: | ||
| 173 | * 1 : u8, 0 = Disabled, 1 = Enabled | ||
| 174 | * Outputs: | ||
| 175 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 176 | */ | ||
| 177 | static void SetSpacialDithering(Interface* self) { | ||
| 178 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 179 | spacial_dithering_enabled = cmd_buff[1] & 0xF; | ||
| 180 | |||
| 181 | cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0); | ||
| 182 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 183 | |||
| 184 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 185 | } | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Y2R_U::GetSpacialDithering service function | ||
| 189 | * Outputs: | ||
| 190 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 191 | * 2 : u8, 0 = Disabled, 1 = Enabled | ||
| 192 | */ | ||
| 193 | static void GetSpacialDithering(Interface* self) { | ||
| 194 | IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0xA, 2, 0); | ||
| 195 | rb.Push(RESULT_SUCCESS); | ||
| 196 | rb.Push(spacial_dithering_enabled != 0); | ||
| 197 | |||
| 198 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 199 | } | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Y2R_U::SetTemporalDithering service function | ||
| 203 | * Inputs: | ||
| 204 | * 1 : u8, 0 = Disabled, 1 = Enabled | ||
| 205 | * Outputs: | ||
| 206 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 207 | */ | ||
| 208 | static void SetTemporalDithering(Interface* self) { | ||
| 209 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 210 | temporal_dithering_enabled = cmd_buff[1] & 0xF; | ||
| 211 | |||
| 212 | cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0); | ||
| 213 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 214 | |||
| 215 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * Y2R_U::GetTemporalDithering service function | ||
| 220 | * Outputs: | ||
| 221 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 222 | * 2 : u8, 0 = Disabled, 1 = Enabled | ||
| 223 | */ | ||
| 224 | static void GetTemporalDithering(Interface* self) { | ||
| 225 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 226 | |||
| 227 | cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0); | ||
| 228 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 229 | cmd_buff[2] = temporal_dithering_enabled; | ||
| 230 | |||
| 231 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * Y2R_U::SetTransferEndInterrupt service function | ||
| 236 | * Inputs: | ||
| 237 | * 1 : u8, 0 = Disabled, 1 = Enabled | ||
| 238 | * Outputs: | ||
| 239 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 240 | */ | ||
| 241 | static void SetTransferEndInterrupt(Interface* self) { | ||
| 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 243 | transfer_end_interrupt_enabled = cmd_buff[1] & 0xf; | ||
| 244 | |||
| 245 | cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0); | ||
| 246 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 247 | |||
| 248 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Y2R_U::GetTransferEndInterrupt service function | ||
| 253 | * Outputs: | ||
| 254 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 255 | * 2 : u8, 0 = Disabled, 1 = Enabled | ||
| 256 | */ | ||
| 257 | static void GetTransferEndInterrupt(Interface* self) { | ||
| 258 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 259 | |||
| 260 | cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0); | ||
| 261 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 262 | cmd_buff[2] = transfer_end_interrupt_enabled; | ||
| 263 | |||
| 264 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 265 | } | ||
| 266 | |||
| 267 | /** | ||
| 268 | * Y2R_U::GetTransferEndEvent service function | ||
| 269 | * Outputs: | ||
| 270 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 271 | * 3 : The handle of the completion event | ||
| 272 | */ | ||
| 273 | static void GetTransferEndEvent(Interface* self) { | ||
| 274 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 275 | |||
| 276 | cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0); | ||
| 277 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 278 | cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).Unwrap(); | ||
| 279 | |||
| 280 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 281 | } | ||
| 282 | |||
| 283 | static void SetSendingY(Interface* self) { | ||
| 284 | // The helper should be passed by argument to the function | ||
| 285 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x00100102); | ||
| 286 | conversion.src_Y.address = rp.Pop<u32>(); | ||
| 287 | conversion.src_Y.image_size = rp.Pop<u32>(); | ||
| 288 | conversion.src_Y.transfer_unit = rp.Pop<u32>(); | ||
| 289 | conversion.src_Y.gap = rp.Pop<u32>(); | ||
| 290 | Kernel::Handle src_process_handle = rp.PopHandle(); | ||
| 291 | |||
| 292 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 293 | rb.Push(RESULT_SUCCESS); | ||
| 294 | |||
| 295 | LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, " | ||
| 296 | "src_process_handle=0x%08X", | ||
| 297 | conversion.src_Y.image_size, conversion.src_Y.transfer_unit, conversion.src_Y.gap, | ||
| 298 | src_process_handle); | ||
| 299 | } | ||
| 300 | |||
| 301 | static void SetSendingU(Interface* self) { | ||
| 302 | // The helper should be passed by argument to the function | ||
| 303 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x00110102); | ||
| 304 | conversion.src_U.address = rp.Pop<u32>(); | ||
| 305 | conversion.src_U.image_size = rp.Pop<u32>(); | ||
| 306 | conversion.src_U.transfer_unit = rp.Pop<u32>(); | ||
| 307 | conversion.src_U.gap = rp.Pop<u32>(); | ||
| 308 | Kernel::Handle src_process_handle = rp.PopHandle(); | ||
| 309 | |||
| 310 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 311 | rb.Push(RESULT_SUCCESS); | ||
| 312 | |||
| 313 | LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, " | ||
| 314 | "src_process_handle=0x%08X", | ||
| 315 | conversion.src_U.image_size, conversion.src_U.transfer_unit, conversion.src_U.gap, | ||
| 316 | src_process_handle); | ||
| 317 | } | ||
| 318 | |||
| 319 | static void SetSendingV(Interface* self) { | ||
| 320 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 321 | |||
| 322 | conversion.src_V.address = cmd_buff[1]; | ||
| 323 | conversion.src_V.image_size = cmd_buff[2]; | ||
| 324 | conversion.src_V.transfer_unit = cmd_buff[3]; | ||
| 325 | conversion.src_V.gap = cmd_buff[4]; | ||
| 326 | |||
| 327 | cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0); | ||
| 328 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 329 | |||
| 330 | LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, " | ||
| 331 | "src_process_handle=0x%08X", | ||
| 332 | conversion.src_V.image_size, conversion.src_V.transfer_unit, conversion.src_V.gap, | ||
| 333 | cmd_buff[6]); | ||
| 334 | } | ||
| 335 | |||
| 336 | static void SetSendingYUYV(Interface* self) { | ||
| 337 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 338 | |||
| 339 | conversion.src_YUYV.address = cmd_buff[1]; | ||
| 340 | conversion.src_YUYV.image_size = cmd_buff[2]; | ||
| 341 | conversion.src_YUYV.transfer_unit = cmd_buff[3]; | ||
| 342 | conversion.src_YUYV.gap = cmd_buff[4]; | ||
| 343 | |||
| 344 | cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0); | ||
| 345 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 346 | |||
| 347 | LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, " | ||
| 348 | "src_process_handle=0x%08X", | ||
| 349 | conversion.src_YUYV.image_size, conversion.src_YUYV.transfer_unit, | ||
| 350 | conversion.src_YUYV.gap, cmd_buff[6]); | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | ||
| 354 | * Y2R::IsFinishedSendingYuv service function | ||
| 355 | * Output: | ||
| 356 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 357 | * 2 : u8, 0 = Not Finished, 1 = Finished | ||
| 358 | */ | ||
| 359 | static void IsFinishedSendingYuv(Interface* self) { | ||
| 360 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 361 | |||
| 362 | cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0); | ||
| 363 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 364 | cmd_buff[2] = 1; | ||
| 365 | |||
| 366 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 367 | } | ||
| 368 | |||
| 369 | /** | ||
| 370 | * Y2R::IsFinishedSendingY service function | ||
| 371 | * Output: | ||
| 372 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 373 | * 2 : u8, 0 = Not Finished, 1 = Finished | ||
| 374 | */ | ||
| 375 | static void IsFinishedSendingY(Interface* self) { | ||
| 376 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 377 | |||
| 378 | cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0); | ||
| 379 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 380 | cmd_buff[2] = 1; | ||
| 381 | |||
| 382 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 383 | } | ||
| 384 | |||
| 385 | /** | ||
| 386 | * Y2R::IsFinishedSendingU service function | ||
| 387 | * Output: | ||
| 388 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 389 | * 2 : u8, 0 = Not Finished, 1 = Finished | ||
| 390 | */ | ||
| 391 | static void IsFinishedSendingU(Interface* self) { | ||
| 392 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 393 | |||
| 394 | cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0); | ||
| 395 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 396 | cmd_buff[2] = 1; | ||
| 397 | |||
| 398 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 399 | } | ||
| 400 | |||
| 401 | /** | ||
| 402 | * Y2R::IsFinishedSendingV service function | ||
| 403 | * Output: | ||
| 404 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 405 | * 2 : u8, 0 = Not Finished, 1 = Finished | ||
| 406 | */ | ||
| 407 | static void IsFinishedSendingV(Interface* self) { | ||
| 408 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 409 | |||
| 410 | cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0); | ||
| 411 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 412 | cmd_buff[2] = 1; | ||
| 413 | |||
| 414 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 415 | } | ||
| 416 | |||
| 417 | static void SetReceiving(Interface* self) { | ||
| 418 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 419 | |||
| 420 | conversion.dst.address = cmd_buff[1]; | ||
| 421 | conversion.dst.image_size = cmd_buff[2]; | ||
| 422 | conversion.dst.transfer_unit = cmd_buff[3]; | ||
| 423 | conversion.dst.gap = cmd_buff[4]; | ||
| 424 | |||
| 425 | cmd_buff[0] = IPC::MakeHeader(0x18, 1, 0); | ||
| 426 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 427 | |||
| 428 | LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, " | ||
| 429 | "dst_process_handle=0x%08X", | ||
| 430 | conversion.dst.image_size, conversion.dst.transfer_unit, conversion.dst.gap, | ||
| 431 | cmd_buff[6]); | ||
| 432 | } | ||
| 433 | |||
| 434 | /** | ||
| 435 | * Y2R::IsFinishedReceiving service function | ||
| 436 | * Output: | ||
| 437 | * 1 : Result of the function, 0 on success, otherwise error code | ||
| 438 | * 2 : u8, 0 = Not Finished, 1 = Finished | ||
| 439 | */ | ||
| 440 | static void IsFinishedReceiving(Interface* self) { | ||
| 441 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 442 | |||
| 443 | cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0); | ||
| 444 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 445 | cmd_buff[2] = 1; | ||
| 446 | |||
| 447 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 448 | } | ||
| 449 | |||
| 450 | static void SetInputLineWidth(Interface* self) { | ||
| 451 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 452 | |||
| 453 | cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0); | ||
| 454 | cmd_buff[1] = conversion.SetInputLineWidth(cmd_buff[1]).raw; | ||
| 455 | |||
| 456 | LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]); | ||
| 457 | } | ||
| 458 | |||
| 459 | static void GetInputLineWidth(Interface* self) { | ||
| 460 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 461 | |||
| 462 | cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0); | ||
| 463 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 464 | cmd_buff[2] = conversion.input_line_width; | ||
| 465 | |||
| 466 | LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width); | ||
| 467 | } | ||
| 468 | |||
| 469 | static void SetInputLines(Interface* self) { | ||
| 470 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 471 | |||
| 472 | cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0); | ||
| 473 | cmd_buff[1] = conversion.SetInputLines(cmd_buff[1]).raw; | ||
| 474 | |||
| 475 | LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]); | ||
| 476 | } | ||
| 477 | |||
| 478 | static void GetInputLines(Interface* self) { | ||
| 479 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 480 | |||
| 481 | cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0); | ||
| 482 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 483 | cmd_buff[2] = static_cast<u32>(conversion.input_lines); | ||
| 484 | |||
| 485 | LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines); | ||
| 486 | } | ||
| 487 | |||
| 488 | static void SetCoefficient(Interface* self) { | ||
| 489 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 490 | |||
| 491 | const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]); | ||
| 492 | std::memcpy(conversion.coefficients.data(), coefficients, sizeof(CoefficientSet)); | ||
| 493 | |||
| 494 | cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0); | ||
| 495 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 496 | |||
| 497 | LOG_DEBUG(Service_Y2R, "called coefficients=[%hX, %hX, %hX, %hX, %hX, %hX, %hX, %hX]", | ||
| 498 | coefficients[0], coefficients[1], coefficients[2], coefficients[3], coefficients[4], | ||
| 499 | coefficients[5], coefficients[6], coefficients[7]); | ||
| 500 | } | ||
| 501 | |||
| 502 | static void GetCoefficient(Interface* self) { | ||
| 503 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 504 | |||
| 505 | cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0); | ||
| 506 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 507 | std::memcpy(&cmd_buff[2], conversion.coefficients.data(), sizeof(CoefficientSet)); | ||
| 508 | |||
| 509 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 510 | } | ||
| 511 | |||
| 512 | static void SetStandardCoefficient(Interface* self) { | ||
| 513 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 514 | |||
| 515 | u32 index = cmd_buff[1]; | ||
| 516 | |||
| 517 | cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0); | ||
| 518 | cmd_buff[1] = conversion.SetStandardCoefficient((StandardCoefficient)index).raw; | ||
| 519 | |||
| 520 | LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index); | ||
| 521 | } | ||
| 522 | |||
| 523 | static void GetStandardCoefficient(Interface* self) { | ||
| 524 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 525 | |||
| 526 | u32 index = cmd_buff[1]; | ||
| 527 | |||
| 528 | if (index < ARRAY_SIZE(standard_coefficients)) { | ||
| 529 | cmd_buff[0] = IPC::MakeHeader(0x21, 5, 0); | ||
| 530 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 531 | std::memcpy(&cmd_buff[2], &standard_coefficients[index], sizeof(CoefficientSet)); | ||
| 532 | |||
| 533 | LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u ", index); | ||
| 534 | } else { | ||
| 535 | cmd_buff[0] = IPC::MakeHeader(0x21, 1, 0); | ||
| 536 | cmd_buff[1] = ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::CAM, | ||
| 537 | ErrorSummary::InvalidArgument, ErrorLevel::Usage) | ||
| 538 | .raw; | ||
| 539 | |||
| 540 | LOG_ERROR(Service_Y2R, "called standard_coefficient=%u The argument is invalid!", index); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | static void SetAlpha(Interface* self) { | ||
| 545 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 546 | |||
| 547 | conversion.alpha = cmd_buff[1]; | ||
| 548 | |||
| 549 | cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0); | ||
| 550 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 551 | |||
| 552 | LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha); | ||
| 553 | } | ||
| 554 | |||
| 555 | static void GetAlpha(Interface* self) { | ||
| 556 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 557 | |||
| 558 | cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0); | ||
| 559 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 560 | cmd_buff[2] = conversion.alpha; | ||
| 561 | |||
| 562 | LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha); | ||
| 563 | } | ||
| 564 | |||
| 565 | static void SetDitheringWeightParams(Interface* self) { | ||
| 566 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x24, 8, 0); // 0x240200 | ||
| 567 | rp.PopRaw(dithering_weight_params); | ||
| 568 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||
| 569 | rb.Push(RESULT_SUCCESS); | ||
| 570 | |||
| 571 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 572 | } | ||
| 573 | |||
| 574 | static void GetDitheringWeightParams(Interface* self) { | ||
| 575 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 576 | |||
| 577 | cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0); | ||
| 578 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 579 | std::memcpy(&cmd_buff[2], &dithering_weight_params, sizeof(DitheringWeightParams)); | ||
| 580 | |||
| 581 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 582 | } | ||
| 583 | |||
| 584 | static void StartConversion(Interface* self) { | ||
| 585 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 586 | |||
| 587 | // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( | ||
| 588 | u32 total_output_size = | ||
| 589 | conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); | ||
| 590 | Memory::RasterizerFlushVirtualRegion(conversion.dst.address, total_output_size, | ||
| 591 | Memory::FlushMode::FlushAndInvalidate); | ||
| 592 | |||
| 593 | HW::Y2R::PerformConversion(conversion); | ||
| 594 | |||
| 595 | completion_event->Signal(); | ||
| 596 | |||
| 597 | cmd_buff[0] = IPC::MakeHeader(0x26, 1, 0); | ||
| 598 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 599 | |||
| 600 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 601 | } | ||
| 602 | |||
| 603 | static void StopConversion(Interface* self) { | ||
| 604 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 605 | |||
| 606 | cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0); | ||
| 607 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 608 | |||
| 609 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 610 | } | ||
| 611 | |||
| 612 | /** | ||
| 613 | * Y2R_U::IsBusyConversion service function | ||
| 614 | * Outputs: | ||
| 615 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 616 | * 2 : 1 if there's a conversion running, otherwise 0. | ||
| 617 | */ | ||
| 618 | static void IsBusyConversion(Interface* self) { | ||
| 619 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 620 | |||
| 621 | cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0); | ||
| 622 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 623 | cmd_buff[2] = 0; // StartConversion always finishes immediately | ||
| 624 | |||
| 625 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 626 | } | ||
| 627 | |||
| 628 | /** | ||
| 629 | * Y2R_U::SetPackageParameter service function | ||
| 630 | */ | ||
| 631 | static void SetPackageParameter(Interface* self) { | ||
| 632 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 633 | |||
| 634 | auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]); | ||
| 635 | |||
| 636 | conversion.input_format = params->input_format; | ||
| 637 | conversion.output_format = params->output_format; | ||
| 638 | conversion.rotation = params->rotation; | ||
| 639 | conversion.block_alignment = params->block_alignment; | ||
| 640 | |||
| 641 | ResultCode result = conversion.SetInputLineWidth(params->input_line_width); | ||
| 642 | |||
| 643 | if (result.IsError()) | ||
| 644 | goto cleanup; | ||
| 645 | |||
| 646 | result = conversion.SetInputLines(params->input_lines); | ||
| 647 | |||
| 648 | if (result.IsError()) | ||
| 649 | goto cleanup; | ||
| 650 | |||
| 651 | result = conversion.SetStandardCoefficient(params->standard_coefficient); | ||
| 652 | |||
| 653 | if (result.IsError()) | ||
| 654 | goto cleanup; | ||
| 655 | |||
| 656 | conversion.padding = params->padding; | ||
| 657 | conversion.alpha = params->alpha; | ||
| 658 | |||
| 659 | cleanup: | ||
| 660 | cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0); | ||
| 661 | cmd_buff[1] = result.raw; | ||
| 662 | |||
| 663 | LOG_DEBUG( | ||
| 664 | Service_Y2R, | ||
| 665 | "called input_format=%hhu output_format=%hhu rotation=%hhu block_alignment=%hhu " | ||
| 666 | "input_line_width=%hu input_lines=%hu standard_coefficient=%hhu reserved=%hhu alpha=%hX", | ||
| 667 | params->input_format, params->output_format, params->rotation, params->block_alignment, | ||
| 668 | params->input_line_width, params->input_lines, params->standard_coefficient, | ||
| 669 | params->padding, params->alpha); | ||
| 670 | } | ||
| 671 | |||
| 672 | static void PingProcess(Interface* self) { | ||
| 673 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 674 | |||
| 675 | cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0); | ||
| 676 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 677 | cmd_buff[2] = 0; | ||
| 678 | |||
| 679 | LOG_WARNING(Service_Y2R, "(STUBBED) called"); | ||
| 680 | } | ||
| 681 | |||
| 682 | static void DriverInitialize(Interface* self) { | ||
| 683 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 684 | |||
| 685 | conversion.input_format = InputFormat::YUV422_Indiv8; | ||
| 686 | conversion.output_format = OutputFormat::RGBA8; | ||
| 687 | conversion.rotation = Rotation::None; | ||
| 688 | conversion.block_alignment = BlockAlignment::Linear; | ||
| 689 | conversion.coefficients.fill(0); | ||
| 690 | conversion.SetInputLineWidth(1024); | ||
| 691 | conversion.SetInputLines(1024); | ||
| 692 | conversion.alpha = 0; | ||
| 693 | |||
| 694 | ConversionBuffer zero_buffer = {}; | ||
| 695 | conversion.src_Y = zero_buffer; | ||
| 696 | conversion.src_U = zero_buffer; | ||
| 697 | conversion.src_V = zero_buffer; | ||
| 698 | conversion.dst = zero_buffer; | ||
| 699 | |||
| 700 | completion_event->Clear(); | ||
| 701 | |||
| 702 | cmd_buff[0] = IPC::MakeHeader(0x2B, 1, 0); | ||
| 703 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 704 | |||
| 705 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 706 | } | ||
| 707 | |||
| 708 | static void DriverFinalize(Interface* self) { | ||
| 709 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 710 | |||
| 711 | cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0); | ||
| 712 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 713 | |||
| 714 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 715 | } | ||
| 716 | |||
| 717 | static void GetPackageParameter(Interface* self) { | ||
| 718 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 719 | |||
| 720 | cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0); | ||
| 721 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 722 | std::memcpy(&cmd_buff[2], &conversion, sizeof(ConversionParameters)); | ||
| 723 | |||
| 724 | LOG_DEBUG(Service_Y2R, "called"); | ||
| 725 | } | ||
| 726 | |||
| 727 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 728 | {0x00010040, SetInputFormat, "SetInputFormat"}, | ||
| 729 | {0x00020000, GetInputFormat, "GetInputFormat"}, | ||
| 730 | {0x00030040, SetOutputFormat, "SetOutputFormat"}, | ||
| 731 | {0x00040000, GetOutputFormat, "GetOutputFormat"}, | ||
| 732 | {0x00050040, SetRotation, "SetRotation"}, | ||
| 733 | {0x00060000, GetRotation, "GetRotation"}, | ||
| 734 | {0x00070040, SetBlockAlignment, "SetBlockAlignment"}, | ||
| 735 | {0x00080000, GetBlockAlignment, "GetBlockAlignment"}, | ||
| 736 | {0x00090040, SetSpacialDithering, "SetSpacialDithering"}, | ||
| 737 | {0x000A0000, GetSpacialDithering, "GetSpacialDithering"}, | ||
| 738 | {0x000B0040, SetTemporalDithering, "SetTemporalDithering"}, | ||
| 739 | {0x000C0000, GetTemporalDithering, "GetTemporalDithering"}, | ||
| 740 | {0x000D0040, SetTransferEndInterrupt, "SetTransferEndInterrupt"}, | ||
| 741 | {0x000E0000, GetTransferEndInterrupt, "GetTransferEndInterrupt"}, | ||
| 742 | {0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"}, | ||
| 743 | {0x00100102, SetSendingY, "SetSendingY"}, | ||
| 744 | {0x00110102, SetSendingU, "SetSendingU"}, | ||
| 745 | {0x00120102, SetSendingV, "SetSendingV"}, | ||
| 746 | {0x00130102, SetSendingYUYV, "SetSendingYUYV"}, | ||
| 747 | {0x00140000, IsFinishedSendingYuv, "IsFinishedSendingYuv"}, | ||
| 748 | {0x00150000, IsFinishedSendingY, "IsFinishedSendingY"}, | ||
| 749 | {0x00160000, IsFinishedSendingU, "IsFinishedSendingU"}, | ||
| 750 | {0x00170000, IsFinishedSendingV, "IsFinishedSendingV"}, | ||
| 751 | {0x00180102, SetReceiving, "SetReceiving"}, | ||
| 752 | {0x00190000, IsFinishedReceiving, "IsFinishedReceiving"}, | ||
| 753 | {0x001A0040, SetInputLineWidth, "SetInputLineWidth"}, | ||
| 754 | {0x001B0000, GetInputLineWidth, "GetInputLineWidth"}, | ||
| 755 | {0x001C0040, SetInputLines, "SetInputLines"}, | ||
| 756 | {0x001D0000, GetInputLines, "GetInputLines"}, | ||
| 757 | {0x001E0100, SetCoefficient, "SetCoefficient"}, | ||
| 758 | {0x001F0000, GetCoefficient, "GetCoefficient"}, | ||
| 759 | {0x00200040, SetStandardCoefficient, "SetStandardCoefficient"}, | ||
| 760 | {0x00210040, GetStandardCoefficient, "GetStandardCoefficient"}, | ||
| 761 | {0x00220040, SetAlpha, "SetAlpha"}, | ||
| 762 | {0x00230000, GetAlpha, "GetAlpha"}, | ||
| 763 | {0x00240200, SetDitheringWeightParams, "SetDitheringWeightParams"}, | ||
| 764 | {0x00250000, GetDitheringWeightParams, "GetDitheringWeightParams"}, | ||
| 765 | {0x00260000, StartConversion, "StartConversion"}, | ||
| 766 | {0x00270000, StopConversion, "StopConversion"}, | ||
| 767 | {0x00280000, IsBusyConversion, "IsBusyConversion"}, | ||
| 768 | {0x002901C0, SetPackageParameter, "SetPackageParameter"}, | ||
| 769 | {0x002A0000, PingProcess, "PingProcess"}, | ||
| 770 | {0x002B0000, DriverInitialize, "DriverInitialize"}, | ||
| 771 | {0x002C0000, DriverFinalize, "DriverFinalize"}, | ||
| 772 | {0x002D0000, GetPackageParameter, "GetPackageParameter"}, | ||
| 773 | }; | ||
| 774 | |||
| 775 | Y2R_U::Y2R_U() { | ||
| 776 | completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed"); | ||
| 777 | std::memset(&conversion, 0, sizeof(conversion)); | ||
| 778 | |||
| 779 | Register(FunctionTable); | ||
| 780 | } | ||
| 781 | |||
| 782 | Y2R_U::~Y2R_U() { | ||
| 783 | completion_event = nullptr; | ||
| 784 | } | ||
| 785 | |||
| 786 | } // namespace Y2R | ||
| 787 | } // namespace Service \ No newline at end of file | ||
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h deleted file mode 100644 index dddeed0be..000000000 --- a/src/core/hle/service/y2r_u.h +++ /dev/null | |||
| @@ -1,139 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace Y2R { | ||
| 15 | |||
| 16 | enum class InputFormat : u8 { | ||
| 17 | /// 8-bit input, with YUV components in separate planes and 4:2:2 subsampling. | ||
| 18 | YUV422_Indiv8 = 0, | ||
| 19 | /// 8-bit input, with YUV components in separate planes and 4:2:0 subsampling. | ||
| 20 | YUV420_Indiv8 = 1, | ||
| 21 | |||
| 22 | /// 16-bit input (only LSB used), with YUV components in separate planes and 4:2:2 subsampling. | ||
| 23 | YUV422_Indiv16 = 2, | ||
| 24 | /// 16-bit input (only LSB used), with YUV components in separate planes and 4:2:0 subsampling. | ||
| 25 | YUV420_Indiv16 = 3, | ||
| 26 | |||
| 27 | /// 8-bit input, with a single interleaved stream in YUYV format and 4:2:2 subsampling. | ||
| 28 | YUYV422_Interleaved = 4, | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum class OutputFormat : u8 { | ||
| 32 | RGBA8 = 0, | ||
| 33 | RGB8 = 1, | ||
| 34 | RGB5A1 = 2, | ||
| 35 | RGB565 = 3, | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum class Rotation : u8 { | ||
| 39 | None = 0, | ||
| 40 | Clockwise_90 = 1, | ||
| 41 | Clockwise_180 = 2, | ||
| 42 | Clockwise_270 = 3, | ||
| 43 | }; | ||
| 44 | |||
| 45 | enum class BlockAlignment : u8 { | ||
| 46 | /// Image is output in linear format suitable for use as a framebuffer. | ||
| 47 | Linear = 0, | ||
| 48 | /// Image is output in tiled PICA format, suitable for use as a texture. | ||
| 49 | Block8x8 = 1, | ||
| 50 | }; | ||
| 51 | |||
| 52 | enum class StandardCoefficient : u8 { | ||
| 53 | /// ITU Rec. BT.601 primaries, with PC ranges. | ||
| 54 | ITU_Rec601 = 0, | ||
| 55 | /// ITU Rec. BT.709 primaries, with PC ranges. | ||
| 56 | ITU_Rec709 = 1, | ||
| 57 | /// ITU Rec. BT.601 primaries, with TV ranges. | ||
| 58 | ITU_Rec601_Scaling = 2, | ||
| 59 | /// ITU Rec. BT.709 primaries, with TV ranges. | ||
| 60 | ITU_Rec709_Scaling = 3, | ||
| 61 | }; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * A set of coefficients configuring the RGB to YUV conversion. Coefficients 0-4 are unsigned 2.8 | ||
| 65 | * fixed pointer numbers representing entries on the conversion matrix, while coefficient 5-7 are | ||
| 66 | * signed 11.5 fixed point numbers added as offsets to the RGB result. | ||
| 67 | * | ||
| 68 | * The overall conversion process formula is: | ||
| 69 | * ``` | ||
| 70 | * R = trunc((c_0 * Y + c_1 * V) + c_5 + 0.75) | ||
| 71 | * G = trunc((c_0 * Y - c_3 * U - c_2 * V) + c_6 + 0.75) | ||
| 72 | * B = trunc((c_0 * Y + c_4 * U ) + c_7 + 0.75) | ||
| 73 | * ``` | ||
| 74 | */ | ||
| 75 | using CoefficientSet = std::array<s16, 8>; | ||
| 76 | |||
| 77 | struct ConversionBuffer { | ||
| 78 | /// Current reading/writing address of this buffer. | ||
| 79 | VAddr address; | ||
| 80 | /// Remaining amount of bytes to be DMAed, does not include the inter-trasfer gap. | ||
| 81 | u32 image_size; | ||
| 82 | /// Size of a single DMA transfer. | ||
| 83 | u16 transfer_unit; | ||
| 84 | /// Amount of bytes to be skipped between copying each `transfer_unit` bytes. | ||
| 85 | u16 gap; | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct ConversionConfiguration { | ||
| 89 | InputFormat input_format; | ||
| 90 | OutputFormat output_format; | ||
| 91 | Rotation rotation; | ||
| 92 | BlockAlignment block_alignment; | ||
| 93 | u16 input_line_width; | ||
| 94 | u16 input_lines; | ||
| 95 | CoefficientSet coefficients; | ||
| 96 | u8 padding; | ||
| 97 | u16 alpha; | ||
| 98 | |||
| 99 | /// Input parameters for the Y (luma) plane | ||
| 100 | ConversionBuffer src_Y, src_U, src_V, src_YUYV; | ||
| 101 | /// Output parameters for the conversion results | ||
| 102 | ConversionBuffer dst; | ||
| 103 | |||
| 104 | ResultCode SetInputLineWidth(u16 width); | ||
| 105 | ResultCode SetInputLines(u16 lines); | ||
| 106 | ResultCode SetStandardCoefficient(StandardCoefficient standard_coefficient); | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct DitheringWeightParams { | ||
| 110 | u16 w0_xEven_yEven; | ||
| 111 | u16 w0_xOdd_yEven; | ||
| 112 | u16 w0_xEven_yOdd; | ||
| 113 | u16 w0_xOdd_yOdd; | ||
| 114 | u16 w1_xEven_yEven; | ||
| 115 | u16 w1_xOdd_yEven; | ||
| 116 | u16 w1_xEven_yOdd; | ||
| 117 | u16 w1_xOdd_yOdd; | ||
| 118 | u16 w2_xEven_yEven; | ||
| 119 | u16 w2_xOdd_yEven; | ||
| 120 | u16 w2_xEven_yOdd; | ||
| 121 | u16 w2_xOdd_yOdd; | ||
| 122 | u16 w3_xEven_yEven; | ||
| 123 | u16 w3_xOdd_yEven; | ||
| 124 | u16 w3_xEven_yOdd; | ||
| 125 | u16 w3_xOdd_yOdd; | ||
| 126 | }; | ||
| 127 | |||
| 128 | class Y2R_U final : public Interface { | ||
| 129 | public: | ||
| 130 | Y2R_U(); | ||
| 131 | ~Y2R_U() override; | ||
| 132 | |||
| 133 | std::string GetPortName() const override { | ||
| 134 | return "y2r:u"; | ||
| 135 | } | ||
| 136 | }; | ||
| 137 | |||
| 138 | } // namespace Y2R | ||
| 139 | } // namespace Service | ||
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 5978ccdd4..833dc5ec9 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <ctime> | 7 | #include <ctime> |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/hle/service/ptm/ptm.h" | ||
| 10 | #include "core/hle/shared_page.h" | 9 | #include "core/hle/shared_page.h" |
| 11 | 10 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -75,8 +74,6 @@ void Init() { | |||
| 75 | shared_page.unknown_value = 0x1; | 74 | shared_page.unknown_value = 0x1; |
| 76 | 75 | ||
| 77 | // Set to a completely full battery | 76 | // Set to a completely full battery |
| 78 | shared_page.battery_state.charge_level.Assign( | ||
| 79 | static_cast<u8>(Service::PTM::ChargeLevels::CompletelyFull)); | ||
| 80 | shared_page.battery_state.is_adapter_connected.Assign(1); | 77 | shared_page.battery_state.is_adapter_connected.Assign(1); |
| 81 | shared_page.battery_state.is_charging.Assign(1); | 78 | shared_page.battery_state.is_charging.Assign(1); |
| 82 | 79 | ||
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp deleted file mode 100644 index e697f84b3..000000000 --- a/src/core/hw/y2r.cpp +++ /dev/null | |||
| @@ -1,382 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/color.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/math_util.h" | ||
| 13 | #include "common/vector_math.h" | ||
| 14 | #include "core/hle/service/y2r_u.h" | ||
| 15 | #include "core/hw/y2r.h" | ||
| 16 | #include "core/memory.h" | ||
| 17 | |||
| 18 | namespace HW { | ||
| 19 | namespace Y2R { | ||
| 20 | |||
| 21 | using namespace Service::Y2R; | ||
| 22 | |||
| 23 | static const size_t MAX_TILES = 1024 / 8; | ||
| 24 | static const size_t TILE_SIZE = 8 * 8; | ||
| 25 | using ImageTile = std::array<u32, TILE_SIZE>; | ||
| 26 | |||
| 27 | /// Converts a image strip from the source YUV format into individual 8x8 RGB32 tiles. | ||
| 28 | static void ConvertYUVToRGB(InputFormat input_format, const u8* input_Y, const u8* input_U, | ||
| 29 | const u8* input_V, ImageTile output[], unsigned int width, | ||
| 30 | unsigned int height, const CoefficientSet& coefficients) { | ||
| 31 | |||
| 32 | for (unsigned int y = 0; y < height; ++y) { | ||
| 33 | for (unsigned int x = 0; x < width; ++x) { | ||
| 34 | s32 Y = 0; | ||
| 35 | s32 U = 0; | ||
| 36 | s32 V = 0; | ||
| 37 | switch (input_format) { | ||
| 38 | case InputFormat::YUV422_Indiv8: | ||
| 39 | case InputFormat::YUV422_Indiv16: | ||
| 40 | Y = input_Y[y * width + x]; | ||
| 41 | U = input_U[(y * width + x) / 2]; | ||
| 42 | V = input_V[(y * width + x) / 2]; | ||
| 43 | break; | ||
| 44 | case InputFormat::YUV420_Indiv8: | ||
| 45 | case InputFormat::YUV420_Indiv16: | ||
| 46 | Y = input_Y[y * width + x]; | ||
| 47 | U = input_U[((y / 2) * width + x) / 2]; | ||
| 48 | V = input_V[((y / 2) * width + x) / 2]; | ||
| 49 | break; | ||
| 50 | case InputFormat::YUYV422_Interleaved: | ||
| 51 | Y = input_Y[(y * width + x) * 2]; | ||
| 52 | U = input_Y[(y * width + (x / 2) * 2) * 2 + 1]; | ||
| 53 | V = input_Y[(y * width + (x / 2) * 2) * 2 + 3]; | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | |||
| 57 | // This conversion process is bit-exact with hardware, as far as could be tested. | ||
| 58 | auto& c = coefficients; | ||
| 59 | s32 cY = c[0] * Y; | ||
| 60 | |||
| 61 | s32 r = cY + c[1] * V; | ||
| 62 | s32 g = cY - c[2] * V - c[3] * U; | ||
| 63 | s32 b = cY + c[4] * U; | ||
| 64 | |||
| 65 | const s32 rounding_offset = 0x18; | ||
| 66 | r = (r >> 3) + c[5] + rounding_offset; | ||
| 67 | g = (g >> 3) + c[6] + rounding_offset; | ||
| 68 | b = (b >> 3) + c[7] + rounding_offset; | ||
| 69 | |||
| 70 | unsigned int tile = x / 8; | ||
| 71 | unsigned int tile_x = x % 8; | ||
| 72 | u32* out = &output[tile][y * 8 + tile_x]; | ||
| 73 | |||
| 74 | using MathUtil::Clamp; | ||
| 75 | *out = ((u32)Clamp(r >> 5, 0, 0xFF) << 24) | ((u32)Clamp(g >> 5, 0, 0xFF) << 16) | | ||
| 76 | ((u32)Clamp(b >> 5, 0, 0xFF) << 8); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Simulates an incoming CDMA transfer. The N parameter is used to automatically convert 16-bit | ||
| 82 | /// formats to 8-bit. | ||
| 83 | template <size_t N> | ||
| 84 | static void ReceiveData(u8* output, ConversionBuffer& buf, size_t amount_of_data) { | ||
| 85 | const u8* input = Memory::GetPointer(buf.address); | ||
| 86 | |||
| 87 | size_t output_unit = buf.transfer_unit / N; | ||
| 88 | ASSERT(amount_of_data % output_unit == 0); | ||
| 89 | |||
| 90 | while (amount_of_data > 0) { | ||
| 91 | for (size_t i = 0; i < output_unit; ++i) { | ||
| 92 | output[i] = input[i * N]; | ||
| 93 | } | ||
| 94 | |||
| 95 | output += output_unit; | ||
| 96 | input += buf.transfer_unit + buf.gap; | ||
| 97 | |||
| 98 | buf.address += buf.transfer_unit + buf.gap; | ||
| 99 | buf.image_size -= buf.transfer_unit; | ||
| 100 | amount_of_data -= output_unit; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Convert intermediate RGB32 format to the final output format while simulating an outgoing CDMA | ||
| 105 | /// transfer. | ||
| 106 | static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data, | ||
| 107 | OutputFormat output_format, u8 alpha) { | ||
| 108 | |||
| 109 | u8* output = Memory::GetPointer(buf.address); | ||
| 110 | |||
| 111 | while (amount_of_data > 0) { | ||
| 112 | u8* unit_end = output + buf.transfer_unit; | ||
| 113 | while (output < unit_end) { | ||
| 114 | u32 color = *input++; | ||
| 115 | Math::Vec4<u8> col_vec{(u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha}; | ||
| 116 | |||
| 117 | switch (output_format) { | ||
| 118 | case OutputFormat::RGBA8: | ||
| 119 | Color::EncodeRGBA8(col_vec, output); | ||
| 120 | output += 4; | ||
| 121 | break; | ||
| 122 | case OutputFormat::RGB8: | ||
| 123 | Color::EncodeRGB8(col_vec, output); | ||
| 124 | output += 3; | ||
| 125 | break; | ||
| 126 | case OutputFormat::RGB5A1: | ||
| 127 | Color::EncodeRGB5A1(col_vec, output); | ||
| 128 | output += 2; | ||
| 129 | break; | ||
| 130 | case OutputFormat::RGB565: | ||
| 131 | Color::EncodeRGB565(col_vec, output); | ||
| 132 | output += 2; | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | |||
| 136 | amount_of_data -= 1; | ||
| 137 | } | ||
| 138 | |||
| 139 | output += buf.gap; | ||
| 140 | buf.address += buf.transfer_unit + buf.gap; | ||
| 141 | buf.image_size -= buf.transfer_unit; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | static const u8 linear_lut[TILE_SIZE] = { | ||
| 146 | // clang-format off | ||
| 147 | 0, 1, 2, 3, 4, 5, 6, 7, | ||
| 148 | 8, 9, 10, 11, 12, 13, 14, 15, | ||
| 149 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
| 150 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
| 151 | 32, 33, 34, 35, 36, 37, 38, 39, | ||
| 152 | 40, 41, 42, 43, 44, 45, 46, 47, | ||
| 153 | 48, 49, 50, 51, 52, 53, 54, 55, | ||
| 154 | 56, 57, 58, 59, 60, 61, 62, 63, | ||
| 155 | // clang-format on | ||
| 156 | }; | ||
| 157 | |||
| 158 | static const u8 morton_lut[TILE_SIZE] = { | ||
| 159 | // clang-format off | ||
| 160 | 0, 1, 4, 5, 16, 17, 20, 21, | ||
| 161 | 2, 3, 6, 7, 18, 19, 22, 23, | ||
| 162 | 8, 9, 12, 13, 24, 25, 28, 29, | ||
| 163 | 10, 11, 14, 15, 26, 27, 30, 31, | ||
| 164 | 32, 33, 36, 37, 48, 49, 52, 53, | ||
| 165 | 34, 35, 38, 39, 50, 51, 54, 55, | ||
| 166 | 40, 41, 44, 45, 56, 57, 60, 61, | ||
| 167 | 42, 43, 46, 47, 58, 59, 62, 63, | ||
| 168 | // clang-format on | ||
| 169 | }; | ||
| 170 | |||
| 171 | static void RotateTile0(const ImageTile& input, ImageTile& output, int height, | ||
| 172 | const u8 out_map[64]) { | ||
| 173 | for (int i = 0; i < height * 8; ++i) { | ||
| 174 | output[out_map[i]] = input[i]; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | static void RotateTile90(const ImageTile& input, ImageTile& output, int height, | ||
| 179 | const u8 out_map[64]) { | ||
| 180 | int out_i = 0; | ||
| 181 | for (int x = 0; x < 8; ++x) { | ||
| 182 | for (int y = height - 1; y >= 0; --y) { | ||
| 183 | output[out_map[out_i++]] = input[y * 8 + x]; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | static void RotateTile180(const ImageTile& input, ImageTile& output, int height, | ||
| 189 | const u8 out_map[64]) { | ||
| 190 | int out_i = 0; | ||
| 191 | for (int i = height * 8 - 1; i >= 0; --i) { | ||
| 192 | output[out_map[out_i++]] = input[i]; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | static void RotateTile270(const ImageTile& input, ImageTile& output, int height, | ||
| 197 | const u8 out_map[64]) { | ||
| 198 | int out_i = 0; | ||
| 199 | for (int x = 8 - 1; x >= 0; --x) { | ||
| 200 | for (int y = 0; y < height; ++y) { | ||
| 201 | output[out_map[out_i++]] = input[y * 8 + x]; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | static void WriteTileToOutput(u32* output, const ImageTile& tile, int height, int line_stride) { | ||
| 207 | for (int y = 0; y < height; ++y) { | ||
| 208 | for (int x = 0; x < 8; ++x) { | ||
| 209 | output[y * line_stride + x] = tile[y * 8 + x]; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | /** | ||
| 215 | * Performs a Y2R colorspace conversion. | ||
| 216 | * | ||
| 217 | * The Y2R hardware implements hardware-accelerated YUV to RGB colorspace conversions. It is most | ||
| 218 | * commonly used for video playback or to display camera input to the screen. | ||
| 219 | * | ||
| 220 | * The conversion process is quite configurable, and can be divided in distinct steps. From | ||
| 221 | * observation, it appears that the hardware buffers a single 8-pixel tall strip of image data | ||
| 222 | * internally and converts it in one go before writing to the output and loading the next strip. | ||
| 223 | * | ||
| 224 | * The steps taken to convert one strip of image data are: | ||
| 225 | * | ||
| 226 | * - The hardware receives data via CDMA (http://3dbrew.org/wiki/Corelink_DMA_Engines), which is | ||
| 227 | * presumably stored in one or more internal buffers. This process can be done in several separate | ||
| 228 | * transfers, as long as they don't exceed the size of the internal image buffer. This allows | ||
| 229 | * flexibility in input strides. | ||
| 230 | * - The input data is decoded into a YUV tuple. Several formats are suported, see the `InputFormat` | ||
| 231 | * enum. | ||
| 232 | * - The YUV tuple is converted, using fixed point calculations, to RGB. This step can be configured | ||
| 233 | * using a set of coefficients to support different colorspace standards. See `CoefficientSet`. | ||
| 234 | * - The strip can be optionally rotated 90, 180 or 270 degrees. Since each strip is processed | ||
| 235 | * independently, this notably rotates each *strip*, not the entire image. This means that for 90 | ||
| 236 | * or 270 degree rotations, the output will be in terms of several 8 x height images, and for any | ||
| 237 | * non-zero rotation the strips will have to be re-arranged so that the parts of the image will | ||
| 238 | * not be shuffled together. This limitation makes this a feature of somewhat dubious utility. 90 | ||
| 239 | * or 270 degree rotations in images with non-even height don't seem to work properly. | ||
| 240 | * - The data is converted to the output RGB format. See the `OutputFormat` enum. | ||
| 241 | * - The data can be output either linearly line-by-line or in the swizzled 8x8 tile format used by | ||
| 242 | * the PICA. This is decided by the `BlockAlignment` enum. If 8x8 alignment is used, then the | ||
| 243 | * image must have a height divisible by 8. The image width must always be divisible by 8. | ||
| 244 | * - The final data is then CDMAed out to main memory and the next image strip is processed. This | ||
| 245 | * offers the same flexibility as the input stage. | ||
| 246 | * | ||
| 247 | * In this implementation, to avoid the combinatorial explosion of parameter combinations, common | ||
| 248 | * intermediate formats are used and where possible tables or parameters are used instead of | ||
| 249 | * diverging code paths to keep the amount of branches in check. Some steps are also merged to | ||
| 250 | * increase efficiency. | ||
| 251 | * | ||
| 252 | * Output for all valid settings combinations matches hardware, however output in some edge-cases | ||
| 253 | * differs: | ||
| 254 | * | ||
| 255 | * - `Block8x8` alignment with non-mod8 height produces different garbage patterns on the last | ||
| 256 | * strip, especially when combined with rotation. | ||
| 257 | * - Hardware, when using `Linear` alignment with a non-even height and 90 or 270 degree rotation | ||
| 258 | * produces misaligned output on the last strip. This implmentation produces output with the | ||
| 259 | * correct "expected" alignment. | ||
| 260 | * | ||
| 261 | * Hardware behaves strangely (doesn't fire the completion interrupt, for example) in these cases, | ||
| 262 | * so they are believed to be invalid configurations anyway. | ||
| 263 | */ | ||
| 264 | void PerformConversion(ConversionConfiguration& cvt) { | ||
| 265 | ASSERT(cvt.input_line_width % 8 == 0); | ||
| 266 | ASSERT(cvt.block_alignment != BlockAlignment::Block8x8 || cvt.input_lines % 8 == 0); | ||
| 267 | // Tiles per row | ||
| 268 | size_t num_tiles = cvt.input_line_width / 8; | ||
| 269 | ASSERT(num_tiles <= MAX_TILES); | ||
| 270 | |||
| 271 | // Buffer used as a CDMA source/target. | ||
| 272 | std::unique_ptr<u8[]> data_buffer(new u8[cvt.input_line_width * 8 * 4]); | ||
| 273 | // Intermediate storage for decoded 8x8 image tiles. Always stored as RGB32. | ||
| 274 | std::unique_ptr<ImageTile[]> tiles(new ImageTile[num_tiles]); | ||
| 275 | ImageTile tmp_tile; | ||
| 276 | |||
| 277 | // LUT used to remap writes to a tile. Used to allow linear or swizzled output without | ||
| 278 | // requiring two different code paths. | ||
| 279 | const u8* tile_remap = nullptr; | ||
| 280 | switch (cvt.block_alignment) { | ||
| 281 | case BlockAlignment::Linear: | ||
| 282 | tile_remap = linear_lut; | ||
| 283 | break; | ||
| 284 | case BlockAlignment::Block8x8: | ||
| 285 | tile_remap = morton_lut; | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | |||
| 289 | for (unsigned int y = 0; y < cvt.input_lines; y += 8) { | ||
| 290 | unsigned int row_height = std::min(cvt.input_lines - y, 8u); | ||
| 291 | |||
| 292 | // Total size in pixels of incoming data required for this strip. | ||
| 293 | const size_t row_data_size = row_height * cvt.input_line_width; | ||
| 294 | |||
| 295 | u8* input_Y = data_buffer.get(); | ||
| 296 | u8* input_U = input_Y + 8 * cvt.input_line_width; | ||
| 297 | u8* input_V = input_U + 8 * cvt.input_line_width / 2; | ||
| 298 | |||
| 299 | switch (cvt.input_format) { | ||
| 300 | case InputFormat::YUV422_Indiv8: | ||
| 301 | ReceiveData<1>(input_Y, cvt.src_Y, row_data_size); | ||
| 302 | ReceiveData<1>(input_U, cvt.src_U, row_data_size / 2); | ||
| 303 | ReceiveData<1>(input_V, cvt.src_V, row_data_size / 2); | ||
| 304 | break; | ||
| 305 | case InputFormat::YUV420_Indiv8: | ||
| 306 | ReceiveData<1>(input_Y, cvt.src_Y, row_data_size); | ||
| 307 | ReceiveData<1>(input_U, cvt.src_U, row_data_size / 4); | ||
| 308 | ReceiveData<1>(input_V, cvt.src_V, row_data_size / 4); | ||
| 309 | break; | ||
| 310 | case InputFormat::YUV422_Indiv16: | ||
| 311 | ReceiveData<2>(input_Y, cvt.src_Y, row_data_size); | ||
| 312 | ReceiveData<2>(input_U, cvt.src_U, row_data_size / 2); | ||
| 313 | ReceiveData<2>(input_V, cvt.src_V, row_data_size / 2); | ||
| 314 | break; | ||
| 315 | case InputFormat::YUV420_Indiv16: | ||
| 316 | ReceiveData<2>(input_Y, cvt.src_Y, row_data_size); | ||
| 317 | ReceiveData<2>(input_U, cvt.src_U, row_data_size / 4); | ||
| 318 | ReceiveData<2>(input_V, cvt.src_V, row_data_size / 4); | ||
| 319 | break; | ||
| 320 | case InputFormat::YUYV422_Interleaved: | ||
| 321 | input_U = nullptr; | ||
| 322 | input_V = nullptr; | ||
| 323 | ReceiveData<1>(input_Y, cvt.src_YUYV, row_data_size * 2); | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | |||
| 327 | // Note(yuriks): If additional optimization is required, input_format can be moved to a | ||
| 328 | // template parameter, so that its dispatch can be moved to outside the inner loop. | ||
| 329 | ConvertYUVToRGB(cvt.input_format, input_Y, input_U, input_V, tiles.get(), | ||
| 330 | cvt.input_line_width, row_height, cvt.coefficients); | ||
| 331 | |||
| 332 | u32* output_buffer = reinterpret_cast<u32*>(data_buffer.get()); | ||
| 333 | |||
| 334 | for (size_t i = 0; i < num_tiles; ++i) { | ||
| 335 | int image_strip_width = 0; | ||
| 336 | int output_stride = 0; | ||
| 337 | |||
| 338 | switch (cvt.rotation) { | ||
| 339 | case Rotation::None: | ||
| 340 | RotateTile0(tiles[i], tmp_tile, row_height, tile_remap); | ||
| 341 | image_strip_width = cvt.input_line_width; | ||
| 342 | output_stride = 8; | ||
| 343 | break; | ||
| 344 | case Rotation::Clockwise_90: | ||
| 345 | RotateTile90(tiles[i], tmp_tile, row_height, tile_remap); | ||
| 346 | image_strip_width = 8; | ||
| 347 | output_stride = 8 * row_height; | ||
| 348 | break; | ||
| 349 | case Rotation::Clockwise_180: | ||
| 350 | // For 180 and 270 degree rotations we also invert the order of tiles in the strip, | ||
| 351 | // since the rotates are done individually on each tile. | ||
| 352 | RotateTile180(tiles[num_tiles - i - 1], tmp_tile, row_height, tile_remap); | ||
| 353 | image_strip_width = cvt.input_line_width; | ||
| 354 | output_stride = 8; | ||
| 355 | break; | ||
| 356 | case Rotation::Clockwise_270: | ||
| 357 | RotateTile270(tiles[num_tiles - i - 1], tmp_tile, row_height, tile_remap); | ||
| 358 | image_strip_width = 8; | ||
| 359 | output_stride = 8 * row_height; | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | |||
| 363 | switch (cvt.block_alignment) { | ||
| 364 | case BlockAlignment::Linear: | ||
| 365 | WriteTileToOutput(output_buffer, tmp_tile, row_height, image_strip_width); | ||
| 366 | output_buffer += output_stride; | ||
| 367 | break; | ||
| 368 | case BlockAlignment::Block8x8: | ||
| 369 | WriteTileToOutput(output_buffer, tmp_tile, 8, 8); | ||
| 370 | output_buffer += TILE_SIZE; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | // Note(yuriks): If additional optimization is required, output_format can be moved to a | ||
| 376 | // template parameter, so that its dispatch can be moved to outside the inner loop. | ||
| 377 | SendData(reinterpret_cast<u32*>(data_buffer.get()), cvt.dst, (int)row_data_size, | ||
| 378 | cvt.output_format, (u8)cvt.alpha); | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } | ||
diff --git a/src/core/hw/y2r.h b/src/core/hw/y2r.h deleted file mode 100644 index 25fcd781c..000000000 --- a/src/core/hw/y2r.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace Y2R { | ||
| 9 | struct ConversionConfiguration; | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace HW { | ||
| 14 | namespace Y2R { | ||
| 15 | void PerformConversion(Service::Y2R::ConversionConfiguration& cvt); | ||
| 16 | } | ||
| 17 | } | ||
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index efcf1267d..012f7e6c3 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include "audio_core/audio_core.h" | 5 | #include "audio_core/audio_core.h" |
| 6 | #include "core/gdbstub/gdbstub.h" | 6 | #include "core/gdbstub/gdbstub.h" |
| 7 | #include "core/hle/service/hid/hid.h" | 7 | #include "core/hle/service/hid/hid.h" |
| 8 | #include "core/hle/service/ir/ir.h" | ||
| 9 | #include "core/settings.h" | 8 | #include "core/settings.h" |
| 10 | #include "video_core/video_core.h" | 9 | #include "video_core/video_core.h" |
| 11 | 10 | ||
| @@ -33,7 +32,6 @@ void Apply() { | |||
| 33 | AudioCore::EnableStretching(values.enable_audio_stretching); | 32 | AudioCore::EnableStretching(values.enable_audio_stretching); |
| 34 | 33 | ||
| 35 | Service::HID::ReloadInputDevices(); | 34 | Service::HID::ReloadInputDevices(); |
| 36 | Service::IR::ReloadInputDevices(); | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | } // namespace Settings | 37 | } // namespace Settings |
diff --git a/src/core/settings.h b/src/core/settings.h index 8d78cb424..912b2c885 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/service/cam/cam.h" | ||
| 11 | 10 | ||
| 12 | namespace Settings { | 11 | namespace Settings { |
| 13 | 12 | ||
| @@ -122,10 +121,6 @@ struct Values { | |||
| 122 | bool enable_audio_stretching; | 121 | bool enable_audio_stretching; |
| 123 | std::string audio_device_id; | 122 | std::string audio_device_id; |
| 124 | 123 | ||
| 125 | // Camera | ||
| 126 | std::array<std::string, Service::CAM::NumCameras> camera_name; | ||
| 127 | std::array<std::string, Service::CAM::NumCameras> camera_config; | ||
| 128 | |||
| 129 | // Debugging | 124 | // Debugging |
| 130 | bool use_gdbstub; | 125 | bool use_gdbstub; |
| 131 | u16 gdbstub_port; | 126 | u16 gdbstub_port; |