Compare commits
230 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3ebfd2481 | |||
| e8a025b4f8 | |||
| f82efe9f65 | |||
| e5c2ec223a | |||
| dbcdb3523b | |||
| 1e398e6c36 | |||
| 55d740fffa | |||
| f6c5507873 | |||
| de7c92d7c4 | |||
| f35c14fb73 | |||
| c1a8a508bc | |||
| 9d4a2de72b | |||
| 5693434b8a | |||
| 47c5c37bed | |||
| a540d248f3 | |||
| bbb6b58aa4 | |||
| 736a31e4ff | |||
| 6060685609 | |||
| 5b85925469 | |||
| 033aa264cf | |||
| 9087fe10e9 | |||
| 6e54615b16 | |||
| c4bfbc6d25 | |||
| e9069dfe76 | |||
| 2be751100b | |||
| ac531aa15f | |||
| 29c7176f55 | |||
| 122435e080 | |||
| 856838f7ce | |||
| 9c739f1506 | |||
| 075d73f076 | |||
| 021e503cc8 | |||
| 1805de0301 | |||
| 9367769fe7 | |||
| a22c5a3880 | |||
| cd0ded7771 | |||
| 351079a4ba | |||
| 62bcb99ba8 | |||
| 13e4ceb990 | |||
| bb94beed15 | |||
| 6e10a0c130 | |||
| e42b4a16b6 | |||
| 182221b9ff | |||
| 2643ea80df | |||
| f94186d3c3 | |||
| bf08bc3c0f | |||
| 871e7cacf6 | |||
| 2fe922aae5 | |||
| ceb65c259a | |||
| 67fd1df762 | |||
| b7f60e9123 | |||
| 3ec027400e | |||
| 42e1db4b0e | |||
| 1968cc7b10 | |||
| a386003b64 | |||
| b3691fc33c | |||
| 7944f271dc | |||
| 5890b96ce5 | |||
| 1f14b58315 | |||
| 3f048770d3 | |||
| cb1487d774 | |||
| 8a214e5530 | |||
| 15ec8d3e44 | |||
| a4362765a6 | |||
| e1838f51a3 | |||
| 97bd6d6418 | |||
| 40f3e2fbf1 | |||
| b70a205a96 | |||
| 3d8eca92f9 | |||
| d6d60f7104 | |||
| bdb7c11d8e | |||
| 8f605b542c | |||
| 2688fb1aa2 | |||
| d100de27ee | |||
| cf023aa8ec | |||
| 7eb17f3aa5 | |||
| 8014dd8259 | |||
| 2df19ef0fd | |||
| 016c6feb49 | |||
| 36c302fa32 | |||
| 6f90dff293 | |||
| ab0c0a469c | |||
| 92da86290c | |||
| 0f4f18265f | |||
| c6cac2ffaa | |||
| 5792a72c29 | |||
| e58090c9c7 | |||
| ed98afdebc | |||
| e46074a2e3 | |||
| 0c5bdc7241 | |||
| cb49c3b64c | |||
| 35862b21d6 | |||
| 4366a21eae | |||
| 1166ca3a57 | |||
| 6fed48b3a4 | |||
| f36b5dfd18 | |||
| 91695a453b | |||
| 55c77dd25b | |||
| 6ed6e6e18e | |||
| 725aacb4bc | |||
| 3547248ec2 | |||
| 82188b2f79 | |||
| 5467d39bc3 | |||
| 27ff00acb1 | |||
| f1b770a8f0 | |||
| 9c9b4616c3 | |||
| e7b6389e44 | |||
| a13fd5f7cc | |||
| 9b771bcb8f | |||
| 94151097b9 | |||
| ca6bf06ef7 | |||
| f017335fef | |||
| f764223f93 | |||
| 46e835f2d6 | |||
| bb2e407772 | |||
| 0a6bd8b236 | |||
| 432d754d7d | |||
| 740c349820 | |||
| 8df3aed2f1 | |||
| 16939b1a6e | |||
| 60d54d911e | |||
| e2b81ae5fe | |||
| b095a0242d | |||
| 2506594c50 | |||
| 7d5683c63c | |||
| 055ee84024 | |||
| ae59ffc56c | |||
| 1c13c74295 | |||
| a71498d163 | |||
| a661c547d8 | |||
| 737e1ca101 | |||
| 87a9be8dec | |||
| ffeb5cdd8d | |||
| 3ba95402fd | |||
| 8dd3baa562 | |||
| daf7936095 | |||
| 627022bef9 | |||
| f3fcc15ad5 | |||
| 35e7f36a39 | |||
| d82cad3fb3 | |||
| cd2981ee12 | |||
| 0c0f5b7ccc | |||
| a546ecbb12 | |||
| 952b271092 | |||
| a090a380be | |||
| cbd79df233 | |||
| c6c11c1553 | |||
| 2528cf7c54 | |||
| 6b973c5986 | |||
| 40f062f749 | |||
| 29a56496bf | |||
| 41a103c0fc | |||
| 66ed1c1872 | |||
| 6f0929df82 | |||
| d1dd54cbfa | |||
| 8f43b05d6b | |||
| f902cc2a2b | |||
| 451b1bba26 | |||
| 494cc992eb | |||
| f603dc9763 | |||
| 4df49631de | |||
| e1c74cea10 | |||
| f7292c776b | |||
| 2007d0e4a0 | |||
| f403d27941 | |||
| 1d7abac84b | |||
| 50791cb974 | |||
| 2ad9acf795 | |||
| 47938541c2 | |||
| 1f079d9566 | |||
| 3f4315e4c6 | |||
| d6f565e5da | |||
| 7ec66db22c | |||
| 2feb40f14d | |||
| 2cd9e1ecb6 | |||
| b566c98258 | |||
| 689f9a75a7 | |||
| b143ce8134 | |||
| 1b5c87ab6a | |||
| 2afaa7aed7 | |||
| fe57f39676 | |||
| 4bc5469f52 | |||
| f8d31d1ae1 | |||
| fff6155bc3 | |||
| 80480fe3f7 | |||
| ed4553806a | |||
| f2d3212de9 | |||
| a16c261131 | |||
| 58d1c7c77a | |||
| 56c9730a16 | |||
| e3a2ca96bd | |||
| 3fbee093b2 | |||
| cb092af3f0 | |||
| 2f15876524 | |||
| 9a7c172f76 | |||
| 5e16fe4579 | |||
| e4dc73f61e | |||
| 9bf19b04f6 | |||
| 47cd0586ee | |||
| 2311fa7c84 | |||
| 00d76fc5f5 | |||
| a3fa64fcc4 | |||
| e29ced29fa | |||
| 7e76c1642c | |||
| fca72beb2d | |||
| eb7c2314f6 | |||
| 4da4ecb1ff | |||
| 3346de365a | |||
| d600183583 | |||
| 0f1ff5f34e | |||
| d0e6eafe23 | |||
| 74d203fbe3 | |||
| 7ffc42c397 | |||
| 4e14b64bfc | |||
| 0cfeb2e8d7 | |||
| 79e32127b3 | |||
| 799579c8d2 | |||
| 3e7af5fbd7 | |||
| 34d0d94df0 | |||
| 55a33342cc | |||
| 70a97fb5c7 | |||
| e3fb9b5e00 | |||
| e0895a8581 | |||
| 07694609fb | |||
| 60c4032b68 | |||
| e37e1d24f9 | |||
| c0e5ecc399 | |||
| 82b78cde73 | |||
| fe91066f46 | |||
| 780240e697 |
@@ -1,13 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2020 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
path_classifiers:
|
||||
library: "externals"
|
||||
extraction:
|
||||
cpp:
|
||||
prepare:
|
||||
packages:
|
||||
- "libsdl2-dev"
|
||||
- "qtmultimedia5-dev"
|
||||
- "libtbb-dev"
|
||||
- "libjack-jackd2-dev"
|
||||
@@ -83,5 +83,3 @@ If you wish to support us a different way, please join our [Discord](https://dis
|
||||
## License
|
||||
|
||||
yuzu is licensed under the GPLv3 (or any later version). Refer to the [LICENSE.txt](https://github.com/yuzu-emu/yuzu/blob/master/LICENSE.txt) file.
|
||||
|
||||
The [Skyline-Emulator Team](https://github.com/skyline-emu/skyline) may choose to use the code from these contributors under the GPL-3.0-or-later OR MPL-2.0: [FernandoS27](https://github.com/FernandoS27), [lioncash](https://github.com/lioncash), [bunnei](https://github.com/bunnei), [ReinUsesLisp](https://github.com/ReinUsesLisp), [Morph1984](https://github.com/Morph1984), [ogniK5377](https://github.com/ogniK5377), [german77](https://github.com/german77), [ameerj](https://github.com/ameerj), [Kelebek1](https://github.com/Kelebek1) and [lat9nq](https://github.com/lat9nq)
|
||||
|
||||
Vendored
+2
-2
@@ -1372,8 +1372,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Interfície de memòria ampliada (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+1
-1
@@ -1364,7 +1364,7 @@ Tato možnost zlepšuje rychlost díky závislosti na sémantice cmpxchg pro zaj
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
|
||||
Vendored
+2
-2
@@ -1380,8 +1380,8 @@ Dette vil bandlyse både vedkommendes forum-brugernavn og IP-adresse.</translati
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Udvidet hukommelsesopsætning (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1360,8 +1360,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Erweitertes Speicherlayout (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1364,8 +1364,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Διάταξη εκτεταμένης μνήμης (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+47
-47
@@ -381,17 +381,17 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/>
|
||||
<source>Output Device:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dispositivo de salida:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/>
|
||||
<source>Input Device:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dispositivo de entrada:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/>
|
||||
<source>Sound Output Mode:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Método de salida de sonido:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/>
|
||||
@@ -1383,8 +1383,8 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Interfaz de memoria extendida (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation>Interfaz de memoria extendida (8GB DRAM)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
@@ -1638,7 +1638,7 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/>
|
||||
<source>AMD FidelityFX™️ Super Resolution</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>AMD FidelityFX™️ Super Resolution</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics.ui" line="489"/>
|
||||
@@ -1753,12 +1753,12 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
|
||||
<source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Activa la decodificación de texturas asíncrona de ASTC, lo cuál podría reducir la duración de los parones. Esta función es experimental.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/>
|
||||
<source>Decode ASTC textures asynchronously (Hack)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Decodificar texturas ASTC de manera asíncrona (Hack)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/>
|
||||
@@ -2268,12 +2268,12 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2710"/>
|
||||
<source>Enable direct JoyCon driver</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Activar driver directo JoyCon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/>
|
||||
<source>Enable direct Pro Controller driver [EXPERIMENTAL]</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Activar driver directo Pro Controller [EXPERIMENTAL]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/>
|
||||
@@ -2637,7 +2637,7 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="399"/>
|
||||
<source>Turbo button</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Botón Turbo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="407"/>
|
||||
@@ -3339,7 +3339,7 @@ UUID: %2</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/>
|
||||
<source>Virtual Ring Sensor Parameters</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Parámetros del sensor Ring virtual</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/>
|
||||
@@ -3361,29 +3361,29 @@ UUID: %2</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="233"/>
|
||||
<source>Direct Joycon Driver</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Driver directo del JoyCon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="293"/>
|
||||
<source>Enable Ring Input</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Activar entrada del Ring</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Activar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/>
|
||||
<source>Ring Sensor Value</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Valor del sensor Ring</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="314"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="282"/>
|
||||
<source>Not connected</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>No conectado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="344"/>
|
||||
@@ -3414,12 +3414,12 @@ UUID: %2</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="279"/>
|
||||
<source>Error enabling ring input</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Error al activar la entrada del Ring</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="285"/>
|
||||
<source>Direct Joycon driver is not enabled</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>El driver directo JoyCon no está activo.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="290"/>
|
||||
@@ -3429,17 +3429,17 @@ UUID: %2</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="302"/>
|
||||
<source>The current mapped device doesn't support the ring controller</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>El dispositivo de entrada actual no soporta el control Ring.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="306"/>
|
||||
<source>The current mapped device doesn't have a ring attached</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>El dispositivo de entrada actual no tiene puesto el Ring</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="310"/>
|
||||
<source>Unexpected driver result %1</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Resultado inesperado del driver %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="333"/>
|
||||
@@ -4498,12 +4498,12 @@ Arrastra los puntos para cambiar de posición, o haz doble clic en las celdas de
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="47"/>
|
||||
<source>Server Address</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dirección del Servidor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="54"/>
|
||||
<source><html><head/><body><p>Server address of the host</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p>Dirección del servidor del anfitrión</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="64"/>
|
||||
@@ -4617,12 +4617,12 @@ Arrastra los puntos para cambiar de posición, o haz doble clic en las celdas de
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1230"/>
|
||||
<source>Emulated mouse is enabled</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>El ratón emulado está activado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1231"/>
|
||||
<source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>La entrada de un ratón real y la panoramización del ratón son incompatibles. Por favor, desactive el ratón emulado en la configuración avanzada de entrada para permitir así la panoramización del ratón.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1453"/>
|
||||
@@ -5489,13 +5489,13 @@ Por favor, utiliza esta función sólo para instalar actualizaciones y DLCs.</tr
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="4069"/>
|
||||
<source>VOLUME: MUTE</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>VOLUMEN: SILENCIO</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="4072"/>
|
||||
<source>VOLUME: %1%</source>
|
||||
<comment>Volume percentage (e.g. 50%)</comment>
|
||||
<translation type="unfinished"/>
|
||||
<translation>VOLUMEN: %1%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="4153"/>
|
||||
@@ -6227,7 +6227,7 @@ Mensaje de depuración: </translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/>
|
||||
<source>Hide Empty Rooms</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ocultar salas vacías</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/lobby.ui" line="90"/>
|
||||
@@ -7152,12 +7152,12 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/>
|
||||
<source>Stick L</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Palanca L</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/>
|
||||
<source>Stick R</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Palanca R</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
|
||||
@@ -7214,19 +7214,19 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="191"/>
|
||||
<source>%1%2%3%4</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1%2%3%4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="205"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="229"/>
|
||||
<source>%1%2%3Hat %4</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1%2%3Rotación %4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="223"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="238"/>
|
||||
<source>%1%2%3Button %4</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1%2%3Botón %4</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -7647,7 +7647,7 @@ Por favor, inténtalo de nuevo o contacta con el desarrollador del software.</tr
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
|
||||
<source>Profile Creator</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Creador de perfil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
|
||||
@@ -7658,57 +7658,57 @@ Por favor, inténtalo de nuevo o contacta con el desarrollador del software.</tr
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
|
||||
<source>Profile Icon Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Editor de icono de perfil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
|
||||
<source>Profile Nickname Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Editor de nombre de perfil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
|
||||
<source>Who will receive the points?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Quién recibirá los puntos?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
|
||||
<source>Who is using Nintendo eShop?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Quién va a utilizar Nintendo eShop?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
|
||||
<source>Who is making this purchase?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Quién está haciendo la compra?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
|
||||
<source>Who is posting?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Quién está publicando esto?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
|
||||
<source>Select a user to link to a Nintendo Account.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Elige un usuario para vincularlo a una Cuenta Nintendo.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
|
||||
<source>Change settings for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Para qué usuario desea cambiar la configuración?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
|
||||
<source>Format data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Para qué usuario se borrarán sus datos?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
|
||||
<source>Which user will be transferred to another console?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿Qué usuario será transferido a otra consola?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
|
||||
<source>Send save data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>¿A qué usuario se le enviarán los datos de guardado?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
|
||||
@@ -7774,7 +7774,7 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/>
|
||||
<source>[%1] %2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>[%1] %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/>
|
||||
|
||||
Vendored
+14
-14
@@ -1382,8 +1382,8 @@ Cette option améliore la vitesse en réduisant la précision des instructions f
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Disposition de la mémoire étendue (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation>Disposition de la mémoire étendue (8 Go de DRAM)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
@@ -7637,7 +7637,7 @@ Veuillez essayer à nouveau ou contactez le développeur du logiciel.</translati
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
|
||||
<source>Profile Creator</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Créateur de profil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
|
||||
@@ -7648,57 +7648,57 @@ Veuillez essayer à nouveau ou contactez le développeur du logiciel.</translati
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
|
||||
<source>Profile Icon Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Éditeur d'icônes de profil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
|
||||
<source>Profile Nickname Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Éditeur de surnom de profil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
|
||||
<source>Who will receive the points?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Qui recevra les points ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
|
||||
<source>Who is using Nintendo eShop?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Qui utilise le Nintendo eShop ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
|
||||
<source>Who is making this purchase?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Qui effectue cet achat ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
|
||||
<source>Who is posting?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Qui publie ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
|
||||
<source>Select a user to link to a Nintendo Account.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Sélectionnez un utilisateur à associer à un compte Nintendo.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
|
||||
<source>Change settings for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Modifier les paramètres pour quel utilisateur ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
|
||||
<source>Format data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Formater les données pour quel utilisateur ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
|
||||
<source>Which user will be transferred to another console?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Quel utilisateur sera transféré sur une autre console ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
|
||||
<source>Send save data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Envoyer les données de sauvegarde pour quel utilisateur ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1339,8 +1339,8 @@ Memungkinkan berbagai macam optimasi IR.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Tata letak memori yang diperluas (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+7
-7
@@ -1368,8 +1368,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Layout di memoria esteso (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
@@ -1846,7 +1846,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="52"/>
|
||||
<source>Restore Defaults</source>
|
||||
<translation>Ripristina predefiniti</translation>
|
||||
<translation>Ripristina predefinite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/>
|
||||
@@ -1894,7 +1894,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/>
|
||||
<source>Restore Default</source>
|
||||
<translation>Ripristina predefinito</translation>
|
||||
<translation>Ripristina predefinita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/>
|
||||
@@ -3886,7 +3886,7 @@ UUID: %2</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/>
|
||||
<source>Pause execution during loads</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Metti in pausa l'esecuzione durante i caricamenti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/>
|
||||
@@ -5352,7 +5352,7 @@ Configurazione &gt; Web.</translation>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3949"/>
|
||||
<source>Scale: %1x</source>
|
||||
<comment>%1 is the resolution scaling factor</comment>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Risoluzione: %1x</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3952"/>
|
||||
@@ -5601,7 +5601,7 @@ Desideri uscire comunque?</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/bootmanager.cpp" line="992"/>
|
||||
<source>yuzu has not been compiled with OpenGL support.</source>
|
||||
<translation>yuzu non è stato compilato con il supporto OpenGL.</translation>
|
||||
<translation>yuzu è stato compilato senza il supporto a OpenGL.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/bootmanager.cpp" line="1016"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1383,8 +1383,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>拡張メモリレイアウト(6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1384,8 +1384,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>확장 메모리 레이아웃(6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1355,8 +1355,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Utvidet minneutforming (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+979
-937
File diff suppressed because it is too large
Load Diff
Vendored
+2
-2
@@ -1377,8 +1377,8 @@ Gdy ta opcja jest włączona, niedopasowanie jest uruchamiane tylko wtedy, gdy d
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Rozszerzony układ pamięci (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1383,8 +1383,8 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Layout de memória extendida (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1373,8 +1373,8 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Layout de memória extendida (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+106
-69
@@ -381,17 +381,17 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/>
|
||||
<source>Output Device:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Устройство вывода:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/>
|
||||
<source>Input Device:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Устройство ввода:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/>
|
||||
<source>Sound Output Mode:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Режим вывода звука:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/>
|
||||
@@ -551,13 +551,13 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div>
|
||||
</source>
|
||||
<translation>
|
||||
<div>Эта опция повышает скорость, уменьшая точность сложенных умноженных инструкций на ЦП без поддержки FMA.</div>
|
||||
<div>Эта опция повышает скорость за счет снижения точности инструкций fused-multiply-add на ЦП без встроенной поддержки FMA.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
|
||||
<source>Unfuse FMA (improve performance on CPUs without FMA)</source>
|
||||
<translation>Не использовать FMA (улучшает производительность на ЦП без FMA)</translation>
|
||||
<translation>Отключить FMA (улучшает производительность на ЦП без FMA)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="113"/>
|
||||
@@ -565,7 +565,7 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div>
|
||||
</source>
|
||||
<translation>
|
||||
<div>Эта опция повышает скорость некоторых аппроксимирующих функций с плавающей точкой за счет использования менее точных нативных приближений.</div>
|
||||
<div>Эта опция повышает скорость некоторых приближенных функций с плавающей точкой за счет использования менее точных нативных приближений</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -579,13 +579,13 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div>
|
||||
</source>
|
||||
<translation>
|
||||
<div>Эта опция улучшает скорость 32-битных ASIMD-функций с плавающей запятой путём работы с некорректными режимами округления.</div>
|
||||
<div>Эта опция повышает скорость работы 32-битных ASIMD-функций с плавающей запятой, работая с неправильными режимами округления.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/>
|
||||
<source>Faster ASIMD instructions (32 bits only)</source>
|
||||
<translation>Более быстрые инструкции ASIMD (только 32 бит)</translation>
|
||||
<translation>Ускоренные инструкции ASIMD (только 32 бит)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/>
|
||||
@@ -593,20 +593,22 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div>
|
||||
</source>
|
||||
<translation>
|
||||
<div>Эта опция повышает скорость, убирая проверку на NaN. Обратите внимание, что это также снижает точность некоторых инструкций с плавающей точкой.</div>
|
||||
<div>Эта опция повышает скорость, удаляя проверку NaN. Обратите внимание, что это также снижает точность некоторых инструкций с плавающей точкой.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/>
|
||||
<source>Inaccurate NaN handling</source>
|
||||
<translation>Неправильная обработка NaN</translation>
|
||||
<translation>Неточная обработка NaN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/>
|
||||
<source>
|
||||
<div>This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Эта опция повышает скорость за счет исключения проверки безопасности перед каждым чтением/записью памяти в гостевом режиме. Отключение этой опции может позволить игре читать/записывать память эмулятора.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/>
|
||||
@@ -618,12 +620,14 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Эта опция повышает скорость, полагаясь только на семантику cmpxchg для обеспечения безопасности инструкций исключительного доступа. Обратите внимание, что это может привести к полным зависаниям и другим условиям гонки.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/>
|
||||
<source>Ignore global monitor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Игнорировать глобальный мониторинг</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/>
|
||||
@@ -660,7 +664,11 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div>
|
||||
<div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Эта оптимизация ускоряет доступ гостевой программы к памяти.</div>
|
||||
<div style="white-space: nowrap"> Включение этой оптимизации встраивает доступ к указателям PageTable::pointers в эмулируемый код.</div>
|
||||
<div style="white-space: nowrap">Отключение этой функции заставляет все обращения к памяти проходить через функции Memory::Read/Memory::Write.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/>
|
||||
@@ -672,7 +680,9 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Эта оптимизация позволяет избежать поиска диспетчера, позволяя эмитированным базовым блокам переходить непосредственно к другим базовым блокам, если конечный ПК статичен.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
|
||||
@@ -684,7 +694,9 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Эта оптимизация позволяет избежать поиска диспетчера, отслеживая потенциальные адреса возврата инструкций BL. Это приближено к тому, что происходит с буфером стека возврата на реальном ЦП.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
|
||||
@@ -696,7 +708,9 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Включите двухуровневую систему диспетчеризации. Сначала используется более быстрый диспетчер, написанный на ассемблере и имеющий небольшой кэш MRU для мест назначения переходов. Если он не справляется, диспетчеризация возвращается к более медленному диспетчеру на C++.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
|
||||
@@ -708,7 +722,9 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Включает IR-оптимизацию, которая уменьшает ненужные обращения к структуре контекста ЦП.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
|
||||
@@ -720,19 +736,23 @@ This would ban both their forum username and their IP address.</source>
|
||||
<source>
|
||||
<div>Enables IR optimizations that involve constant propagation.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Включает IR-оптимизацию, которая включает распространение констант.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
|
||||
<source>Enable constant propagation</source>
|
||||
<translation>Включить постоянное распространение</translation>
|
||||
<translation>Включить распространение констант</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/>
|
||||
<source>
|
||||
<div>Enables miscellaneous IR optimizations.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div>Включает различные IR-оптимизации.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
|
||||
@@ -745,12 +765,15 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div>
|
||||
<div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Если функция включена, смещение срабатывает только тогда, когда доступ пересекает границу страницы.</div>
|
||||
<div style="white-space: nowrap">Если отключено, смещение срабатывает при всех смещенных доступах.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/>
|
||||
<source>Enable misalignment check reduction</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить уменьшение проверки несоосности</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/>
|
||||
@@ -759,12 +782,16 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div>
|
||||
<div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Эта оптимизация ускоряет доступ гостевой программы к памяти.</div>
|
||||
<div style="white-space: nowrap"> Включение этой оптимизации приводит к тому, что чтение/запись гостевой памяти производится непосредственно в память и использует MMU хоста.</div>
|
||||
<div style="white-space: nowrap">Отключение этой функции заставляет все обращения к памяти использовать программную эмуляцию MMU.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/>
|
||||
<source>Enable Host MMU Emulation (general memory instructions)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить эмуляцию MMU хоста (инструкции общей памяти)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/>
|
||||
@@ -773,12 +800,16 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.</div>
|
||||
<div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Эта оптимизация ускоряет доступ гостевой программы к эксклюзивной памяти.</div>
|
||||
<div style="white-space: nowrap">Включение этой оптимизации приводит к тому, что чтение/запись в эксклюзивную память гостя выполняется непосредственно в память и использует MMU хоста.</div>
|
||||
<div style="white-space: nowrap"> Отключение этой функции заставляет все эксклюзивные доступы к памяти использовать эмуляцию программного MMU.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/>
|
||||
<source>Enable Host MMU Emulation (exclusive memory instructions)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить эмуляцию MMU хоста (инструкции исключительной памяти)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/>
|
||||
@@ -786,12 +817,15 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div>
|
||||
<div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Эта оптимизация ускоряет обращение гостевой программы к исключительной памяти.</div>
|
||||
<div style="white-space: nowrap">Ее включение снижает накладные расходы, связанные с отказом fastmem при доступе к исключительной памяти.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/>
|
||||
<source>Enable recompilation of exclusive memory instructions</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Разрешить перекомпиляцию инструкций исключительной памяти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="181"/>
|
||||
@@ -799,7 +833,10 @@ This would ban both their forum username and their IP address.</source>
|
||||
<div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div>
|
||||
<div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div>
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>
|
||||
<div style="white-space: nowrap">Эта оптимизация ускоряет обращение к памяти, позволяя успешное обращение к недопустимой памяти.</div>
|
||||
<div style="white-space: nowrap">Включение этой оптимизации снижает накладные расходы на все обращения к памяти и не влияет на программы, которые не обращаются к недопустимой памяти.</div>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="187"/>
|
||||
@@ -917,17 +954,17 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/>
|
||||
<source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source>
|
||||
<translation>Если включено, отключает компилятор макроса Just In Time. Включение опции делает игры медленнее</translation>
|
||||
<translation>Если включено, отключает компилятор макроса Just In Time. Включение этого параметра замедляет работу игр</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
|
||||
<source>Disable Macro JIT</source>
|
||||
<translation>Отключить Macro JIT</translation>
|
||||
<translation>Отключить макрос JIT</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/>
|
||||
<source>When checked, it disables the macro HLE functions. Enabling this makes games run slower</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Если флажок установлен, он отключает функции макроса HLE. Включение этого параметра замедляет работу игр</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="214"/>
|
||||
@@ -947,12 +984,12 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/>
|
||||
<source>When checked, it executes shaders without loop logic changes</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Если включено, шейдеры выполняются без изменения логики цикла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="234"/>
|
||||
<source>Disable Loop safety checks</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Отключить проверку безопасности цикла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/>
|
||||
@@ -967,12 +1004,12 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="257"/>
|
||||
<source>Enable FS Access Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить журнал доступа к ФС</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="264"/>
|
||||
<source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включите эту опцию, чтобы вывести на консоль последний сгенерированный список аудиокоманд. Влияет только на игры, использующие аудио рендерер.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="267"/>
|
||||
@@ -1007,7 +1044,7 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="311"/>
|
||||
<source>Enable Auto-Stub**</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить автоподставку**</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="318"/>
|
||||
@@ -1346,8 +1383,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Расширенная компоновка памяти (6 ГБ DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation>Расширенная компоновка памяти (8 ГБ DRAM)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
@@ -1716,12 +1753,12 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
|
||||
<source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включает асинхронное декодирование текстур ASTC, что может уменьшить фризы при загрузке. Эта функция является экспериментальной.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/>
|
||||
<source>Decode ASTC textures asynchronously (Hack)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Асинхронное декодирование текстур ASTC (Хак)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/>
|
||||
@@ -2236,7 +2273,7 @@ This would ban both their forum username and their IP address.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/>
|
||||
<source>Enable direct Pro Controller driver [EXPERIMENTAL]</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Включить прямой драйвер Pro Controller [ЭКСПЕРИМЕНТАЛЬНО]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/>
|
||||
@@ -4580,12 +4617,12 @@ Drag points to change position, or double-click table cells to edit values.</sou
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1230"/>
|
||||
<source>Emulated mouse is enabled</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Эмулированная мышь включена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1231"/>
|
||||
<source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ввод реальной мыши и панорамирование мышью несовместимы. Пожалуйста, отключите эмулированную мышь в расширенных настройках ввода, чтобы разрешить панорамирование мышью.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1453"/>
|
||||
@@ -7613,7 +7650,7 @@ Please try again or contact the developer of the software.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
|
||||
<source>Profile Creator</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Создатель профиля</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
|
||||
@@ -7624,57 +7661,57 @@ Please try again or contact the developer of the software.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
|
||||
<source>Profile Icon Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Редактор иконки профиля</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
|
||||
<source>Profile Nickname Editor</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Редактор никнейма профиля</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
|
||||
<source>Who will receive the points?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Кто будет получать очки?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
|
||||
<source>Who is using Nintendo eShop?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Кто использует Nintendo eShop?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
|
||||
<source>Who is making this purchase?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Кто совершает эту покупку?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
|
||||
<source>Who is posting?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Кто публикует?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
|
||||
<source>Select a user to link to a Nintendo Account.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Выберите пользователя для привязки к учетной записи Nintendo.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
|
||||
<source>Change settings for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Изменить настройки для какого пользователя?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
|
||||
<source>Format data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Форматировать данные для какого пользователя?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
|
||||
<source>Which user will be transferred to another console?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Какой пользователь будет переходить на другую консоль?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
|
||||
<source>Send save data for which user?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Отправить сохранение какому пользователю?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
|
||||
@@ -7740,7 +7777,7 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/>
|
||||
<source>[%1] %2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>[%1] %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/>
|
||||
@@ -7753,17 +7790,17 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="202"/>
|
||||
<source>runnable</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>runnable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="204"/>
|
||||
<source>paused</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>paused</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="210"/>
|
||||
<source>sleeping</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>sleeping</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="213"/>
|
||||
@@ -7778,32 +7815,32 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="219"/>
|
||||
<source>waiting for condition variable</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>waiting for condition variable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="222"/>
|
||||
<source>waiting for address arbiter</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>waiting for address arbiter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="225"/>
|
||||
<source>waiting for suspend resume</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>waiting for suspend resume</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/>
|
||||
<source>waiting</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>waiting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="233"/>
|
||||
<source>initialized</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>initialized</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="236"/>
|
||||
<source>terminated</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>terminated</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="239"/>
|
||||
@@ -7818,7 +7855,7 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="294"/>
|
||||
<source>ideal</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>ideal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="297"/>
|
||||
@@ -7848,7 +7885,7 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/debugger/wait_tree.cpp" line="309"/>
|
||||
<source>last running ticks = %1</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>last running ticks = %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
Vendored
+35
-35
@@ -122,7 +122,7 @@ p, li { white-space: pre-wrap; }
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/>
|
||||
<source>%1 has been unbanned</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 har haft dess bannlysning upphävd.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/>
|
||||
@@ -242,22 +242,22 @@ Detta kommer bannlysa både dennes användarnamn på forum samt IP-adress.</tran
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="77"/>
|
||||
<source><html><head/><body><p>Does the game boot?</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p>Startar Spelet? </p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="100"/>
|
||||
<source>Yes The game starts to output video or audio</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ja Spelet öppnar till utmatning av video eller audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="107"/>
|
||||
<source>No The game doesn't get past the "Launching..." screen</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Nej Spelet öppnar ej förbi "Startar..." skärmen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="124"/>
|
||||
<source>Yes The game gets past the intro/menu and into gameplay</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ja Spelet öppnar förbi introt/menyn och in i själva spelandet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/compatdb.ui" line="131"/>
|
||||
@@ -1031,7 +1031,7 @@ avgjord kod.</div>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="325"/>
|
||||
<source>Disable Web Applet</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Avaktivera Webbappletten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_debug.ui" line="332"/>
|
||||
@@ -1360,8 +1360,8 @@ avgjord kod.</div>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Utökad minnesöversikt (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
@@ -3320,13 +3320,13 @@ UUID: %2</source>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/>
|
||||
<source>Pull</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dra</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/>
|
||||
<source>Push</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Knuff</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/>
|
||||
@@ -3347,7 +3347,7 @@ UUID: %2</source>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Aktivera</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/>
|
||||
@@ -4493,17 +4493,17 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="97"/>
|
||||
<source>Nickname</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Smeknamn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="111"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Lösenord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="153"/>
|
||||
<source>Connect</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Anslut</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4511,12 +4511,12 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="120"/>
|
||||
<source>Connecting</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ansluter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="125"/>
|
||||
<source>Connect</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Anslut</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4534,7 +4534,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="432"/>
|
||||
<source>Broken Vulkan Installation Detected</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Felaktig Vulkaninstallation Upptäckt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="433"/>
|
||||
@@ -4550,7 +4550,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
|
||||
<location filename="../../src/yuzu/main.cpp" line="874"/>
|
||||
<location filename="../../src/yuzu/main.cpp" line="877"/>
|
||||
<source>Disable Web Applet</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Avaktivera Webbappletten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="878"/>
|
||||
@@ -4591,7 +4591,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1230"/>
|
||||
<source>Emulated mouse is enabled</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Emulerad datormus är aktiverad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="1231"/>
|
||||
@@ -5171,7 +5171,7 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3182"/>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3201"/>
|
||||
<source>Hardware requirements not met</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation> Hårdvarukraven uppfylls ej</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3183"/>
|
||||
@@ -5202,17 +5202,17 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3514"/>
|
||||
<source>TAS Recording</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>TAS Inspelning</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3515"/>
|
||||
<source>Overwrite file of player 1?</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Överskriv spelare 1:s fil?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3541"/>
|
||||
<source>Invalid config detected</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ogiltig konfiguration upptäckt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3542"/>
|
||||
@@ -5223,13 +5223,13 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3712"/>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3740"/>
|
||||
<source>Amiibo</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Amiibo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3712"/>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3740"/>
|
||||
<source>The current amiibo has been removed</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Den aktuella amiibon har avlägsnats</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3717"/>
|
||||
@@ -5240,7 +5240,7 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3717"/>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3752"/>
|
||||
<source>The current game is not looking for amiibos</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Det aktuella spelet letar ej efter amiibos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3723"/>
|
||||
@@ -5260,17 +5260,17 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3746"/>
|
||||
<source>The selected file is not a valid amiibo</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Den valda filen är inte en giltig amiibo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3749"/>
|
||||
<source>The selected file is already on use</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Den valda filen är redan använd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3755"/>
|
||||
<source>An unknown error occurred</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ett okänt fel har inträffat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3807"/>
|
||||
@@ -5285,22 +5285,22 @@ Please, only use this feature to install updates and DLC.</source>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3891"/>
|
||||
<source>TAS state: Running %1/%2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>TAStillstånd: pågående %1/%2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3895"/>
|
||||
<source>TAS state: Recording %1</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>TAStillstånd: spelar in %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3897"/>
|
||||
<source>TAS state: Idle %1/%2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>TAStillstånd: inaktiv %1/%2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3901"/>
|
||||
<source>TAS State: Invalid</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>TAStillstånd: ogiltigt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/main.cpp" line="3915"/>
|
||||
@@ -5902,7 +5902,7 @@ Vill du strunta i detta och avsluta ändå?</translation>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Lösenord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/>
|
||||
@@ -6169,7 +6169,7 @@ Debug Message: </source>
|
||||
<location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/>
|
||||
<location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/>
|
||||
<source>Nickname</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Smeknamn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1368,8 +1368,8 @@ Bu seçenek belleğe yazma/okuma işlemlerindeki güvenlik kontrolünü kaldıra
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Artırılmış hafıza düzeni (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1346,8 +1346,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>Розширене компонування пам'яті (6 ГБ DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation type="unfinished"/>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1380,8 +1380,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>扩展的内存布局 (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation>扩展的内存布局 (8GB DRAM)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+2
-2
@@ -1382,8 +1382,8 @@ This would ban both their forum username and their IP address.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
|
||||
<source>Extended memory layout (6GB DRAM)</source>
|
||||
<translation>扩展的内存布局 (6GB DRAM)</translation>
|
||||
<source>Extended memory layout (8GB DRAM)</source>
|
||||
<translation>扩展的内存布局 (8GB DRAM)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
|
||||
|
||||
Vendored
+1
-1
Submodule externals/cubeb updated: 75d9d125ee...48689ae7a7
Vendored
+1
-1
Submodule externals/dynarmic updated: c08c5a9362...7da378033a
@@ -113,6 +113,9 @@ else()
|
||||
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
|
||||
)
|
||||
|
||||
@@ -436,10 +436,7 @@ void System::Stop() {
|
||||
}
|
||||
|
||||
if (execution_mode == ExecutionMode::Auto) {
|
||||
// Should wait for the system to terminate here, but core timing (should have) already
|
||||
// stopped, so this isn't needed. Find a way to make this definite.
|
||||
|
||||
// terminate_event.Wait();
|
||||
terminate_event.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/sink/sdl2_sink.h"
|
||||
@@ -10,16 +11,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
/**
|
||||
* SDL sink stream, responsible for sinking samples to hardware.
|
||||
|
||||
@@ -72,7 +72,7 @@ MAP_MEMBER(void)::MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInf
|
||||
}
|
||||
}()};
|
||||
|
||||
if (block_end_predecessor->virt >= virt) {
|
||||
if (block_end_predecessor != blocks.begin() && block_end_predecessor->virt >= virt) {
|
||||
// If this block's start would be overlapped by the map then reuse it as a tail
|
||||
// block
|
||||
block_end_predecessor->virt = virt_end;
|
||||
@@ -336,7 +336,7 @@ ALLOC_MEMBER(VaType)::Allocate(VaType size) {
|
||||
ASSERT_MSG(false, "Unexpected allocator state!");
|
||||
}
|
||||
|
||||
auto search_predecessor{this->blocks.begin()};
|
||||
auto search_predecessor{std::next(this->blocks.begin())};
|
||||
auto search_successor{std::next(search_predecessor)};
|
||||
|
||||
while (search_successor != this->blocks.end() &&
|
||||
|
||||
@@ -111,6 +111,8 @@ struct AnalogProperties {
|
||||
float offset{};
|
||||
// Invert direction of the sensor data
|
||||
bool inverted{};
|
||||
// Invert the state if it's converted to a button
|
||||
bool inverted_button{};
|
||||
// Press once to activate, press again to release
|
||||
bool toggle{};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,631 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/parent_of_member.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Forward declare implementation class for Node.
|
||||
namespace impl {
|
||||
|
||||
class IntrusiveListImpl;
|
||||
|
||||
}
|
||||
|
||||
class IntrusiveListNode {
|
||||
YUZU_NON_COPYABLE(IntrusiveListNode);
|
||||
|
||||
private:
|
||||
friend class impl::IntrusiveListImpl;
|
||||
|
||||
IntrusiveListNode* m_prev;
|
||||
IntrusiveListNode* m_next;
|
||||
|
||||
public:
|
||||
constexpr IntrusiveListNode() : m_prev(this), m_next(this) {}
|
||||
|
||||
constexpr bool IsLinked() const {
|
||||
return m_next != this;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void LinkPrev(IntrusiveListNode* node) {
|
||||
// We can't link an already linked node.
|
||||
ASSERT(!node->IsLinked());
|
||||
this->SplicePrev(node, node);
|
||||
}
|
||||
|
||||
constexpr void SplicePrev(IntrusiveListNode* first, IntrusiveListNode* last) {
|
||||
// Splice a range into the list.
|
||||
auto last_prev = last->m_prev;
|
||||
first->m_prev = m_prev;
|
||||
last_prev->m_next = this;
|
||||
m_prev->m_next = first;
|
||||
m_prev = last_prev;
|
||||
}
|
||||
|
||||
constexpr void LinkNext(IntrusiveListNode* node) {
|
||||
// We can't link an already linked node.
|
||||
ASSERT(!node->IsLinked());
|
||||
return this->SpliceNext(node, node);
|
||||
}
|
||||
|
||||
constexpr void SpliceNext(IntrusiveListNode* first, IntrusiveListNode* last) {
|
||||
// Splice a range into the list.
|
||||
auto last_prev = last->m_prev;
|
||||
first->m_prev = this;
|
||||
last_prev->m_next = m_next;
|
||||
m_next->m_prev = last_prev;
|
||||
m_next = first;
|
||||
}
|
||||
|
||||
constexpr void Unlink() {
|
||||
this->Unlink(m_next);
|
||||
}
|
||||
|
||||
constexpr void Unlink(IntrusiveListNode* last) {
|
||||
// Unlink a node from a next node.
|
||||
auto last_prev = last->m_prev;
|
||||
m_prev->m_next = last;
|
||||
last->m_prev = m_prev;
|
||||
last_prev->m_next = this;
|
||||
m_prev = last_prev;
|
||||
}
|
||||
|
||||
constexpr IntrusiveListNode* GetPrev() {
|
||||
return m_prev;
|
||||
}
|
||||
|
||||
constexpr const IntrusiveListNode* GetPrev() const {
|
||||
return m_prev;
|
||||
}
|
||||
|
||||
constexpr IntrusiveListNode* GetNext() {
|
||||
return m_next;
|
||||
}
|
||||
|
||||
constexpr const IntrusiveListNode* GetNext() const {
|
||||
return m_next;
|
||||
}
|
||||
};
|
||||
// DEPRECATED: static_assert(std::is_literal_type<IntrusiveListNode>::value);
|
||||
|
||||
namespace impl {
|
||||
|
||||
class IntrusiveListImpl {
|
||||
YUZU_NON_COPYABLE(IntrusiveListImpl);
|
||||
|
||||
private:
|
||||
IntrusiveListNode m_root_node;
|
||||
|
||||
public:
|
||||
template <bool Const>
|
||||
class Iterator;
|
||||
|
||||
using value_type = IntrusiveListNode;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = Iterator<false>;
|
||||
using const_iterator = Iterator<true>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
template <bool Const>
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename IntrusiveListImpl::value_type;
|
||||
using difference_type = typename IntrusiveListImpl::difference_type;
|
||||
using pointer =
|
||||
std::conditional_t<Const, IntrusiveListImpl::const_pointer, IntrusiveListImpl::pointer>;
|
||||
using reference = std::conditional_t<Const, IntrusiveListImpl::const_reference,
|
||||
IntrusiveListImpl::reference>;
|
||||
|
||||
private:
|
||||
pointer m_node;
|
||||
|
||||
public:
|
||||
constexpr explicit Iterator(pointer n) : m_node(n) {}
|
||||
|
||||
constexpr bool operator==(const Iterator& rhs) const {
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
return m_node;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator++() {
|
||||
m_node = m_node->m_next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() {
|
||||
m_node = m_node->m_prev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int) {
|
||||
const Iterator it{*this};
|
||||
++(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr Iterator operator--(int) {
|
||||
const Iterator it{*this};
|
||||
--(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr operator Iterator<true>() const {
|
||||
return Iterator<true>(m_node);
|
||||
}
|
||||
|
||||
constexpr Iterator<false> GetNonConstIterator() const {
|
||||
return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(m_node));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr IntrusiveListImpl() : m_root_node() {}
|
||||
|
||||
// Iterator accessors.
|
||||
constexpr iterator begin() {
|
||||
return iterator(m_root_node.GetNext());
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(m_root_node.GetNext());
|
||||
}
|
||||
|
||||
constexpr iterator end() {
|
||||
return iterator(std::addressof(m_root_node));
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(std::addressof(m_root_node));
|
||||
}
|
||||
|
||||
constexpr iterator iterator_to(reference v) {
|
||||
// Only allow iterator_to for values in lists.
|
||||
ASSERT(v.IsLinked());
|
||||
return iterator(std::addressof(v));
|
||||
}
|
||||
|
||||
constexpr const_iterator iterator_to(const_reference v) const {
|
||||
// Only allow iterator_to for values in lists.
|
||||
ASSERT(v.IsLinked());
|
||||
return const_iterator(std::addressof(v));
|
||||
}
|
||||
|
||||
// Content management.
|
||||
constexpr bool empty() const {
|
||||
return !m_root_node.IsLinked();
|
||||
}
|
||||
|
||||
constexpr size_type size() const {
|
||||
return static_cast<size_type>(std::distance(this->begin(), this->end()));
|
||||
}
|
||||
|
||||
constexpr reference back() {
|
||||
return *m_root_node.GetPrev();
|
||||
}
|
||||
|
||||
constexpr const_reference back() const {
|
||||
return *m_root_node.GetPrev();
|
||||
}
|
||||
|
||||
constexpr reference front() {
|
||||
return *m_root_node.GetNext();
|
||||
}
|
||||
|
||||
constexpr const_reference front() const {
|
||||
return *m_root_node.GetNext();
|
||||
}
|
||||
|
||||
constexpr void push_back(reference node) {
|
||||
m_root_node.LinkPrev(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void push_front(reference node) {
|
||||
m_root_node.LinkNext(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void pop_back() {
|
||||
m_root_node.GetPrev()->Unlink();
|
||||
}
|
||||
|
||||
constexpr void pop_front() {
|
||||
m_root_node.GetNext()->Unlink();
|
||||
}
|
||||
|
||||
constexpr iterator insert(const_iterator pos, reference node) {
|
||||
pos.GetNonConstIterator()->LinkPrev(std::addressof(node));
|
||||
return iterator(std::addressof(node));
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o) {
|
||||
splice_impl(pos, o.begin(), o.end());
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first) {
|
||||
const_iterator last(first);
|
||||
std::advance(last, 1);
|
||||
splice_impl(pos, first, last);
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first,
|
||||
const_iterator last) {
|
||||
splice_impl(pos, first, last);
|
||||
}
|
||||
|
||||
constexpr iterator erase(const_iterator pos) {
|
||||
if (pos == this->end()) {
|
||||
return this->end();
|
||||
}
|
||||
iterator it(pos.GetNonConstIterator());
|
||||
(it++)->Unlink();
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr void clear() {
|
||||
while (!this->empty()) {
|
||||
this->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
|
||||
if (_first == _last) {
|
||||
return;
|
||||
}
|
||||
iterator pos(_pos.GetNonConstIterator());
|
||||
iterator first(_first.GetNonConstIterator());
|
||||
iterator last(_last.GetNonConstIterator());
|
||||
first->Unlink(std::addressof(*last));
|
||||
pos->SplicePrev(std::addressof(*first), std::addressof(*first));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <class T, class Traits>
|
||||
class IntrusiveList {
|
||||
YUZU_NON_COPYABLE(IntrusiveList);
|
||||
|
||||
private:
|
||||
impl::IntrusiveListImpl m_impl;
|
||||
|
||||
public:
|
||||
template <bool Const>
|
||||
class Iterator;
|
||||
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = Iterator<false>;
|
||||
using const_iterator = Iterator<true>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
template <bool Const>
|
||||
class Iterator {
|
||||
public:
|
||||
friend class Common::IntrusiveList<T, Traits>;
|
||||
|
||||
using ImplIterator =
|
||||
std::conditional_t<Const, Common::impl::IntrusiveListImpl::const_iterator,
|
||||
Common::impl::IntrusiveListImpl::iterator>;
|
||||
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename IntrusiveList::value_type;
|
||||
using difference_type = typename IntrusiveList::difference_type;
|
||||
using pointer =
|
||||
std::conditional_t<Const, IntrusiveList::const_pointer, IntrusiveList::pointer>;
|
||||
using reference =
|
||||
std::conditional_t<Const, IntrusiveList::const_reference, IntrusiveList::reference>;
|
||||
|
||||
private:
|
||||
ImplIterator m_iterator;
|
||||
|
||||
private:
|
||||
constexpr explicit Iterator(ImplIterator it) : m_iterator(it) {}
|
||||
|
||||
constexpr ImplIterator GetImplIterator() const {
|
||||
return m_iterator;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr bool operator==(const Iterator& rhs) const {
|
||||
return m_iterator == rhs.m_iterator;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
return std::addressof(Traits::GetParent(*m_iterator));
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
return Traits::GetParent(*m_iterator);
|
||||
}
|
||||
|
||||
constexpr Iterator& operator++() {
|
||||
++m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() {
|
||||
--m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int) {
|
||||
const Iterator it{*this};
|
||||
++m_iterator;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr Iterator operator--(int) {
|
||||
const Iterator it{*this};
|
||||
--m_iterator;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr operator Iterator<true>() const {
|
||||
return Iterator<true>(m_iterator);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr IntrusiveListNode& GetNode(reference ref) {
|
||||
return Traits::GetNode(ref);
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(const_reference ref) {
|
||||
return Traits::GetNode(ref);
|
||||
}
|
||||
|
||||
static constexpr reference GetParent(IntrusiveListNode& node) {
|
||||
return Traits::GetParent(node);
|
||||
}
|
||||
|
||||
static constexpr const_reference GetParent(IntrusiveListNode const& node) {
|
||||
return Traits::GetParent(node);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr IntrusiveList() : m_impl() {}
|
||||
|
||||
// Iterator accessors.
|
||||
constexpr iterator begin() {
|
||||
return iterator(m_impl.begin());
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(m_impl.begin());
|
||||
}
|
||||
|
||||
constexpr iterator end() {
|
||||
return iterator(m_impl.end());
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(m_impl.end());
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const {
|
||||
return this->begin();
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const {
|
||||
return this->end();
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rbegin() {
|
||||
return reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
constexpr reverse_iterator rend() {
|
||||
return reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const {
|
||||
return this->rbegin();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crend() const {
|
||||
return this->rend();
|
||||
}
|
||||
|
||||
constexpr iterator iterator_to(reference v) {
|
||||
return iterator(m_impl.iterator_to(GetNode(v)));
|
||||
}
|
||||
|
||||
constexpr const_iterator iterator_to(const_reference v) const {
|
||||
return const_iterator(m_impl.iterator_to(GetNode(v)));
|
||||
}
|
||||
|
||||
// Content management.
|
||||
constexpr bool empty() const {
|
||||
return m_impl.empty();
|
||||
}
|
||||
|
||||
constexpr size_type size() const {
|
||||
return m_impl.size();
|
||||
}
|
||||
|
||||
constexpr reference back() {
|
||||
return GetParent(m_impl.back());
|
||||
}
|
||||
|
||||
constexpr const_reference back() const {
|
||||
return GetParent(m_impl.back());
|
||||
}
|
||||
|
||||
constexpr reference front() {
|
||||
return GetParent(m_impl.front());
|
||||
}
|
||||
|
||||
constexpr const_reference front() const {
|
||||
return GetParent(m_impl.front());
|
||||
}
|
||||
|
||||
constexpr void push_back(reference ref) {
|
||||
m_impl.push_back(GetNode(ref));
|
||||
}
|
||||
|
||||
constexpr void push_front(reference ref) {
|
||||
m_impl.push_front(GetNode(ref));
|
||||
}
|
||||
|
||||
constexpr void pop_back() {
|
||||
m_impl.pop_back();
|
||||
}
|
||||
|
||||
constexpr void pop_front() {
|
||||
m_impl.pop_front();
|
||||
}
|
||||
|
||||
constexpr iterator insert(const_iterator pos, reference ref) {
|
||||
return iterator(m_impl.insert(pos.GetImplIterator(), GetNode(ref)));
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl);
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator());
|
||||
}
|
||||
|
||||
constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first,
|
||||
const_iterator last) {
|
||||
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator(),
|
||||
last.GetImplIterator());
|
||||
}
|
||||
|
||||
constexpr iterator erase(const_iterator pos) {
|
||||
return iterator(m_impl.erase(pos.GetImplIterator()));
|
||||
}
|
||||
|
||||
constexpr void clear() {
|
||||
m_impl.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template <auto T, class Derived = Common::impl::GetParentType<T>>
|
||||
class IntrusiveListMemberTraits;
|
||||
|
||||
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
|
||||
class IntrusiveListMemberTraits<Member, Derived> {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraits>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListMemberTraits>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static Derived& GetParent(IntrusiveListNode& node) {
|
||||
return Common::GetParentReference<Member, Derived>(std::addressof(node));
|
||||
}
|
||||
|
||||
static Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return Common::GetParentReference<Member, Derived>(std::addressof(node));
|
||||
}
|
||||
};
|
||||
|
||||
template <auto T, class Derived = Common::impl::GetParentType<T>>
|
||||
class IntrusiveListMemberTraitsByNonConstexprOffsetOf;
|
||||
|
||||
template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
|
||||
class IntrusiveListMemberTraitsByNonConstexprOffsetOf<Member, Derived> {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return parent.*Member;
|
||||
}
|
||||
|
||||
static Derived& GetParent(IntrusiveListNode& node) {
|
||||
return *reinterpret_cast<Derived*>(reinterpret_cast<char*>(std::addressof(node)) -
|
||||
GetOffset());
|
||||
}
|
||||
|
||||
static Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return *reinterpret_cast<const Derived*>(
|
||||
reinterpret_cast<const char*>(std::addressof(node)) - GetOffset());
|
||||
}
|
||||
|
||||
static uintptr_t GetOffset() {
|
||||
return reinterpret_cast<uintptr_t>(std::addressof(reinterpret_cast<Derived*>(0)->*Member));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
class IntrusiveListBaseNode : public IntrusiveListNode {};
|
||||
|
||||
template <class Derived>
|
||||
class IntrusiveListBaseTraits {
|
||||
public:
|
||||
using ListType = IntrusiveList<Derived, IntrusiveListBaseTraits>;
|
||||
|
||||
private:
|
||||
friend class IntrusiveList<Derived, IntrusiveListBaseTraits>;
|
||||
|
||||
static constexpr IntrusiveListNode& GetNode(Derived& parent) {
|
||||
return static_cast<IntrusiveListNode&>(
|
||||
static_cast<IntrusiveListBaseNode<Derived>&>(parent));
|
||||
}
|
||||
|
||||
static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
|
||||
return static_cast<const IntrusiveListNode&>(
|
||||
static_cast<const IntrusiveListBaseNode<Derived>&>(parent));
|
||||
}
|
||||
|
||||
static constexpr Derived& GetParent(IntrusiveListNode& node) {
|
||||
return static_cast<Derived&>(static_cast<IntrusiveListBaseNode<Derived>&>(node));
|
||||
}
|
||||
|
||||
static constexpr Derived const& GetParent(IntrusiveListNode const& node) {
|
||||
return static_cast<const Derived&>(
|
||||
static_cast<const IntrusiveListBaseNode<Derived>&>(node));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -23,7 +23,10 @@ public:
|
||||
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
|
||||
|
||||
~ScratchBuffer() = default;
|
||||
ScratchBuffer(const ScratchBuffer&) = delete;
|
||||
ScratchBuffer& operator=(const ScratchBuffer&) = delete;
|
||||
ScratchBuffer(ScratchBuffer&&) = default;
|
||||
ScratchBuffer& operator=(ScratchBuffer&&) = default;
|
||||
|
||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||
/// The previously held data will remain intact.
|
||||
@@ -87,6 +90,12 @@ public:
|
||||
return buffer_capacity;
|
||||
}
|
||||
|
||||
void swap(ScratchBuffer& other) noexcept {
|
||||
std::swap(last_requested_size, other.last_requested_size);
|
||||
std::swap(buffer_capacity, other.buffer_capacity);
|
||||
std::swap(buffer, other.buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t last_requested_size{};
|
||||
size_t buffer_capacity{};
|
||||
|
||||
@@ -45,6 +45,7 @@ void LogSettings() {
|
||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
||||
log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
|
||||
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
|
||||
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
|
||||
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
|
||||
@@ -60,7 +61,8 @@ void LogSettings() {
|
||||
log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
|
||||
log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
|
||||
log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
|
||||
log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
|
||||
log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
|
||||
log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
|
||||
log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
|
||||
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
|
||||
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
|
||||
@@ -191,7 +193,7 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
|
||||
// Core
|
||||
values.use_multi_core.SetGlobal(true);
|
||||
values.use_extended_memory_layout.SetGlobal(true);
|
||||
values.use_unsafe_extended_memory_layout.SetGlobal(true);
|
||||
|
||||
// CPU
|
||||
values.cpu_accuracy.SetGlobal(true);
|
||||
@@ -205,6 +207,7 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
// Renderer
|
||||
values.fsr_sharpening_slider.SetGlobal(true);
|
||||
values.renderer_backend.SetGlobal(true);
|
||||
values.async_presentation.SetGlobal(true);
|
||||
values.renderer_force_max_clock.SetGlobal(true);
|
||||
values.vulkan_device.SetGlobal(true);
|
||||
values.fullscreen_mode.SetGlobal(true);
|
||||
@@ -221,15 +224,15 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
values.nvdec_emulation.SetGlobal(true);
|
||||
values.accelerate_astc.SetGlobal(true);
|
||||
values.async_astc.SetGlobal(true);
|
||||
values.use_vsync.SetGlobal(true);
|
||||
values.use_reactive_flushing.SetGlobal(true);
|
||||
values.shader_backend.SetGlobal(true);
|
||||
values.use_asynchronous_shaders.SetGlobal(true);
|
||||
values.use_fast_gpu_time.SetGlobal(true);
|
||||
values.use_pessimistic_flushes.SetGlobal(true);
|
||||
values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
|
||||
values.bg_red.SetGlobal(true);
|
||||
values.bg_green.SetGlobal(true);
|
||||
values.bg_blue.SetGlobal(true);
|
||||
values.enable_compute_pipelines.SetGlobal(true);
|
||||
|
||||
// System
|
||||
values.language_index.SetGlobal(true);
|
||||
|
||||
+16
-3
@@ -16,6 +16,13 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
enum class VSyncMode : u32 {
|
||||
Immediate = 0,
|
||||
Mailbox = 1,
|
||||
FIFO = 2,
|
||||
FIFORelaxed = 3,
|
||||
};
|
||||
|
||||
enum class RendererBackend : u32 {
|
||||
OpenGL = 0,
|
||||
Vulkan = 1,
|
||||
@@ -388,7 +395,8 @@ struct Values {
|
||||
|
||||
// Core
|
||||
SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
|
||||
SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
|
||||
SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
|
||||
"use_unsafe_extended_memory_layout"};
|
||||
|
||||
// Cpu
|
||||
SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
|
||||
@@ -422,6 +430,7 @@ struct Values {
|
||||
// Renderer
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{
|
||||
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
|
||||
SwitchableSetting<bool> async_presentation{false, "async_presentation"};
|
||||
SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
|
||||
Setting<bool> renderer_debug{false, "debug"};
|
||||
Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
@@ -454,14 +463,16 @@ struct Values {
|
||||
SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
|
||||
SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
|
||||
SwitchableSetting<bool> async_astc{false, "async_astc"};
|
||||
SwitchableSetting<bool> use_vsync{true, "use_vsync"};
|
||||
Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
|
||||
VSyncMode::FIFORelaxed, "use_vsync"};
|
||||
SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
|
||||
ShaderBackend::SPIRV, "shader_backend"};
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
|
||||
SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
|
||||
SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"};
|
||||
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
|
||||
"use_vulkan_driver_pipeline_cache"};
|
||||
SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"};
|
||||
|
||||
SwitchableSetting<u8> bg_red{0, "bg_red"};
|
||||
SwitchableSetting<u8> bg_green{0, "bg_green"};
|
||||
@@ -525,6 +536,8 @@ struct Values {
|
||||
Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
|
||||
Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
|
||||
|
||||
Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
|
||||
|
||||
// Data Storage
|
||||
Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
|
||||
Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
|
||||
|
||||
@@ -259,6 +259,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RotateFromOrigin(float roll, float pitch, float yaw) {
|
||||
float temp = y;
|
||||
y = std::cos(roll) * y - std::sin(roll) * z;
|
||||
z = std::sin(roll) * temp + std::cos(roll) * z;
|
||||
|
||||
temp = x;
|
||||
x = std::cos(pitch) * x + std::sin(pitch) * z;
|
||||
z = -std::sin(pitch) * temp + std::cos(pitch) * z;
|
||||
|
||||
temp = x;
|
||||
x = std::cos(yaw) * x - std::sin(yaw) * y;
|
||||
y = std::sin(yaw) * temp + std::cos(yaw) * y;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
+11
-10
@@ -555,21 +555,22 @@ add_library(core STATIC
|
||||
hle/service/mnpp/mnpp_app.h
|
||||
hle/service/ncm/ncm.cpp
|
||||
hle/service/ncm/ncm.h
|
||||
hle/service/nfc/mifare_user.cpp
|
||||
hle/service/nfc/mifare_user.h
|
||||
hle/service/nfc/common/amiibo_crypto.cpp
|
||||
hle/service/nfc/common/amiibo_crypto.h
|
||||
hle/service/nfc/common/device.cpp
|
||||
hle/service/nfc/common/device.h
|
||||
hle/service/nfc/common/device_manager.cpp
|
||||
hle/service/nfc/common/device_manager.h
|
||||
hle/service/nfc/mifare_result.h
|
||||
hle/service/nfc/mifare_types.h
|
||||
hle/service/nfc/nfc.cpp
|
||||
hle/service/nfc/nfc.h
|
||||
hle/service/nfc/nfc_device.cpp
|
||||
hle/service/nfc/nfc_device.h
|
||||
hle/service/nfc/nfc_interface.cpp
|
||||
hle/service/nfc/nfc_interface.h
|
||||
hle/service/nfc/nfc_result.h
|
||||
hle/service/nfc/nfc_user.cpp
|
||||
hle/service/nfc/nfc_user.h
|
||||
hle/service/nfp/amiibo_crypto.cpp
|
||||
hle/service/nfp/amiibo_crypto.h
|
||||
hle/service/nfc/nfc_types.h
|
||||
hle/service/nfp/nfp.cpp
|
||||
hle/service/nfp/nfp.h
|
||||
hle/service/nfp/nfp_device.cpp
|
||||
hle/service/nfp/nfp_device.h
|
||||
hle/service/nfp/nfp_interface.cpp
|
||||
hle/service/nfp/nfp_interface.h
|
||||
hle/service/nfp/nfp_result.h
|
||||
|
||||
+8
-3
@@ -137,7 +137,7 @@ struct System::Impl {
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
|
||||
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
@@ -169,7 +169,7 @@ struct System::Impl {
|
||||
void ReinitializeIfNecessary(System& system) {
|
||||
const bool must_reinitialize =
|
||||
is_multicore != Settings::values.use_multi_core.GetValue() ||
|
||||
extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue();
|
||||
extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
|
||||
if (!must_reinitialize) {
|
||||
return;
|
||||
@@ -178,7 +178,7 @@ struct System::Impl {
|
||||
LOG_DEBUG(Kernel, "Re-initializing");
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
|
||||
extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
|
||||
|
||||
Initialize(system);
|
||||
}
|
||||
@@ -293,6 +293,7 @@ struct System::Impl {
|
||||
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
|
||||
Kernel::KProcess::ProcessType::Userland, resource_limit)
|
||||
.IsSuccess());
|
||||
Kernel::KProcess::Register(system.Kernel(), main_process);
|
||||
kernel.MakeApplicationProcess(main_process);
|
||||
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
|
||||
if (load_result != Loader::ResultStatus::Success) {
|
||||
@@ -611,6 +612,10 @@ void System::PrepareReschedule(const u32 core_index) {
|
||||
impl->kernel.PrepareReschedule(core_index);
|
||||
}
|
||||
|
||||
size_t System::GetCurrentHostThreadID() const {
|
||||
return impl->kernel.GetCurrentHostThreadID();
|
||||
}
|
||||
|
||||
PerfStatsResults System::GetAndResetPerfStats() {
|
||||
return impl->GetAndResetPerfStats();
|
||||
}
|
||||
|
||||
@@ -222,6 +222,8 @@ public:
|
||||
/// Prepare the core emulation for a reschedule
|
||||
void PrepareReschedule(u32 core_index);
|
||||
|
||||
[[nodiscard]] size_t GetCurrentHostThreadID() const;
|
||||
|
||||
/// Gets and resets core performance statistics
|
||||
[[nodiscard]] PerfStatsResults GetAndResetPerfStats();
|
||||
|
||||
|
||||
@@ -82,9 +82,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
|
||||
// Only detect account/device saves from the future location.
|
||||
switch (type) {
|
||||
case SaveDataType::SaveData:
|
||||
return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id);
|
||||
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
|
||||
case SaveDataType::DeviceSaveData:
|
||||
return fmt::format("{}/device/{:016X}/1", space_id_path, title_id);
|
||||
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include "core/file_sys/vfs_layered.h"
|
||||
|
||||
@@ -58,11 +59,13 @@ std::string LayeredVfsDirectory::GetFullPath() const {
|
||||
|
||||
std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
|
||||
std::vector<VirtualFile> out;
|
||||
std::set<std::string, std::less<>> out_names;
|
||||
|
||||
for (const auto& layer : dirs) {
|
||||
for (const auto& file : layer->GetFiles()) {
|
||||
if (std::find_if(out.begin(), out.end(), [&file](const VirtualFile& comp) {
|
||||
return comp->GetName() == file->GetName();
|
||||
}) == out.end()) {
|
||||
auto file_name = file->GetName();
|
||||
if (!out_names.contains(file_name)) {
|
||||
out_names.emplace(std::move(file_name));
|
||||
out.push_back(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,23 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
|
||||
|
||||
VectorVfsDirectory::~VectorVfsDirectory() = default;
|
||||
|
||||
VirtualFile VectorVfsDirectory::GetFile(std::string_view file_name) const {
|
||||
if (!optimized_file_index_built) {
|
||||
optimized_file_index.clear();
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
optimized_file_index.emplace(files[i]->GetName(), i);
|
||||
}
|
||||
optimized_file_index_built = true;
|
||||
}
|
||||
|
||||
const auto it = optimized_file_index.find(file_name);
|
||||
if (it != optimized_file_index.end()) {
|
||||
return files[it->second];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
|
||||
return files;
|
||||
}
|
||||
@@ -107,6 +124,7 @@ bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
|
||||
}
|
||||
|
||||
bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
|
||||
optimized_file_index_built = false;
|
||||
return FindAndRemoveVectorElement(files, file_name);
|
||||
}
|
||||
|
||||
@@ -124,6 +142,7 @@ VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
|
||||
}
|
||||
|
||||
void VectorVfsDirectory::AddFile(VirtualFile file) {
|
||||
optimized_file_index_built = false;
|
||||
files.push_back(std::move(file));
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ public:
|
||||
VirtualDir parent = nullptr);
|
||||
~VectorVfsDirectory() override;
|
||||
|
||||
VirtualFile GetFile(std::string_view file_name) const override;
|
||||
std::vector<VirtualFile> GetFiles() const override;
|
||||
std::vector<VirtualDir> GetSubdirectories() const override;
|
||||
bool IsWritable() const override;
|
||||
@@ -126,6 +127,9 @@ private:
|
||||
|
||||
VirtualDir parent;
|
||||
std::string name;
|
||||
|
||||
mutable std::map<std::string, size_t, std::less<>> optimized_file_index;
|
||||
mutable bool optimized_file_index_built{};
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -14,7 +14,7 @@ void DefaultCabinetApplet::Close() const {}
|
||||
|
||||
void DefaultCabinetApplet::ShowCabinetApplet(
|
||||
const CabinetCallback& callback, const CabinetParameters& parameters,
|
||||
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
|
||||
std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
callback(false, {});
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "core/frontend/applets/applet.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
|
||||
namespace Service::NFP {
|
||||
class NfpDevice;
|
||||
} // namespace Service::NFP
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
} // namespace Service::NFC
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
@@ -26,14 +26,14 @@ public:
|
||||
virtual ~CabinetApplet();
|
||||
virtual void ShowCabinetApplet(const CabinetCallback& callback,
|
||||
const CabinetParameters& parameters,
|
||||
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
|
||||
std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
|
||||
};
|
||||
|
||||
class DefaultCabinetApplet final : public CabinetApplet {
|
||||
public:
|
||||
void Close() const override;
|
||||
void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
|
||||
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
|
||||
std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -280,6 +280,10 @@ void EmulatedController::LoadVirtualGamepadParams() {
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
|
||||
virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
|
||||
}
|
||||
|
||||
void EmulatedController::ReloadInput() {
|
||||
@@ -372,6 +376,7 @@ void EmulatedController::ReloadInput() {
|
||||
motion.accel = emulated_motion.GetAcceleration();
|
||||
motion.gyro = emulated_motion.GetGyroscope();
|
||||
motion.rotation = emulated_motion.GetRotations();
|
||||
motion.euler = emulated_motion.GetEulerAngles();
|
||||
motion.orientation = emulated_motion.GetOrientation();
|
||||
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
|
||||
}
|
||||
@@ -547,6 +552,8 @@ void EmulatedController::EnableSystemButtons() {
|
||||
void EmulatedController::DisableSystemButtons() {
|
||||
std::scoped_lock lock{mutex};
|
||||
system_buttons_enabled = false;
|
||||
controller.home_button_state.raw = 0;
|
||||
controller.capture_button_state.raw = 0;
|
||||
}
|
||||
|
||||
void EmulatedController::ResetSystemButtons() {
|
||||
@@ -681,6 +688,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void EmulatedController::StartMotionCalibration() {
|
||||
for (ControllerMotionInfo& motion : controller.motion_values) {
|
||||
motion.emulated.Calibrate();
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
if (index >= controller.button_values.size()) {
|
||||
@@ -730,6 +743,8 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
||||
if (is_configuring) {
|
||||
controller.npad_button_state.raw = NpadButton::None;
|
||||
controller.debug_pad_button_state.raw = 0;
|
||||
controller.home_button_state.raw = 0;
|
||||
controller.capture_button_state.raw = 0;
|
||||
lock.unlock();
|
||||
TriggerOnChange(ControllerTriggerType::Button, false);
|
||||
return;
|
||||
@@ -970,16 +985,12 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||
emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
|
||||
emulated.UpdateRotation(raw_status.delta_timestamp);
|
||||
emulated.UpdateOrientation(raw_status.delta_timestamp);
|
||||
force_update_motion = raw_status.force_update;
|
||||
|
||||
if (is_configuring) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& motion = controller.motion_state[index];
|
||||
motion.accel = emulated.GetAcceleration();
|
||||
motion.gyro = emulated.GetGyroscope();
|
||||
motion.rotation = emulated.GetRotations();
|
||||
motion.euler = emulated.GetEulerAngles();
|
||||
motion.orientation = emulated.GetOrientation();
|
||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
||||
}
|
||||
@@ -1612,19 +1623,6 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
|
||||
|
||||
MotionState EmulatedController::GetMotions() const {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
// Some drivers like mouse motion need constant refreshing
|
||||
if (force_update_motion) {
|
||||
for (auto& device : motion_devices) {
|
||||
if (!device) {
|
||||
continue;
|
||||
}
|
||||
lock.unlock();
|
||||
device->ForceUpdate();
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
return controller.motion_state;
|
||||
}
|
||||
|
||||
@@ -1690,8 +1688,21 @@ void EmulatedController::DeleteCallback(int key) {
|
||||
callback_list.erase(iterator);
|
||||
}
|
||||
|
||||
void EmulatedController::TurboButtonUpdate() {
|
||||
void EmulatedController::StatusUpdate() {
|
||||
turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
|
||||
|
||||
// Some drivers like key motion need constant refreshing
|
||||
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
|
||||
const auto& raw_status = controller.motion_values[index].raw_status;
|
||||
auto& device = motion_devices[index];
|
||||
if (!raw_status.force_update) {
|
||||
continue;
|
||||
}
|
||||
if (!device) {
|
||||
continue;
|
||||
}
|
||||
device->ForceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
NpadButton EmulatedController::GetTurboButtonMask() const {
|
||||
|
||||
@@ -106,6 +106,7 @@ struct ControllerMotion {
|
||||
Common::Vec3f accel{};
|
||||
Common::Vec3f gyro{};
|
||||
Common::Vec3f rotation{};
|
||||
Common::Vec3f euler{};
|
||||
std::array<Common::Vec3f, 3> orientation{};
|
||||
bool is_at_rest{};
|
||||
};
|
||||
@@ -289,6 +290,9 @@ public:
|
||||
*/
|
||||
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
||||
|
||||
/// Auto calibrates the current motion devices
|
||||
void StartMotionCalibration();
|
||||
|
||||
/// Returns the latest button status from the controller with parameters
|
||||
ButtonValues GetButtonsValues() const;
|
||||
|
||||
@@ -414,8 +418,8 @@ public:
|
||||
*/
|
||||
void DeleteCallback(int key);
|
||||
|
||||
/// Swaps the state of the turbo buttons
|
||||
void TurboButtonUpdate();
|
||||
/// Swaps the state of the turbo buttons and updates motion input
|
||||
void StatusUpdate();
|
||||
|
||||
private:
|
||||
/// creates input devices from params
|
||||
@@ -527,7 +531,6 @@ private:
|
||||
bool is_configuring{false};
|
||||
bool system_buttons_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
bool force_update_motion{false};
|
||||
u32 turbo_button_state{0};
|
||||
|
||||
// Temporary values to avoid doing changes while the controller is in configuring mode
|
||||
|
||||
@@ -54,6 +54,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
|
||||
case Common::Input::InputType::Analog:
|
||||
status.value = TransformToTrigger(callback).pressed.value;
|
||||
status.toggle = callback.analog_status.properties.toggle;
|
||||
status.inverted = callback.analog_status.properties.inverted_button;
|
||||
break;
|
||||
case Common::Input::InputType::Trigger:
|
||||
status.value = TransformToTrigger(callback).pressed.value;
|
||||
@@ -61,6 +62,9 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
|
||||
case Common::Input::InputType::Button:
|
||||
status = callback.button_status;
|
||||
break;
|
||||
case Common::Input::InputType::Motion:
|
||||
status.value = std::abs(callback.motion_status.gyro.x.raw_value) > 1.0f;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
|
||||
break;
|
||||
@@ -82,7 +86,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
|
||||
.range = 1.0f,
|
||||
.offset = 0.0f,
|
||||
};
|
||||
status.delta_timestamp = 5000;
|
||||
status.delta_timestamp = 1000;
|
||||
status.force_update = true;
|
||||
status.accel.x = {
|
||||
.value = 0.0f,
|
||||
@@ -226,6 +230,10 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta
|
||||
status = callback.trigger_status;
|
||||
calculate_button_value = false;
|
||||
break;
|
||||
case Common::Input::InputType::Motion:
|
||||
status.analog.properties.range = 1.0f;
|
||||
raw_value = callback.motion_status.accel.x.raw_value;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/hid/motion_input.h"
|
||||
|
||||
@@ -35,11 +37,17 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
|
||||
gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
|
||||
gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
|
||||
|
||||
// Auto adjust drift to minimize drift
|
||||
// Auto adjust gyro_bias to minimize drift
|
||||
if (!IsMoving(IsAtRestRelaxed)) {
|
||||
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
|
||||
}
|
||||
|
||||
// Adjust drift when calibration mode is enabled
|
||||
if (calibration_mode) {
|
||||
gyro_bias = (gyro_bias * 0.99f) + (gyroscope * 0.01f);
|
||||
StopCalibration();
|
||||
}
|
||||
|
||||
if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
|
||||
gyro = {};
|
||||
} else {
|
||||
@@ -51,6 +59,20 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
|
||||
quat = quaternion;
|
||||
}
|
||||
|
||||
void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
|
||||
const float cr = std::cos(euler_angles.x * 0.5f);
|
||||
const float sr = std::sin(euler_angles.x * 0.5f);
|
||||
const float cp = std::cos(euler_angles.y * 0.5f);
|
||||
const float sp = std::sin(euler_angles.y * 0.5f);
|
||||
const float cy = std::cos(euler_angles.z * 0.5f);
|
||||
const float sy = std::sin(euler_angles.z * 0.5f);
|
||||
|
||||
quat.w = cr * cp * cy + sr * sp * sy;
|
||||
quat.xyz.x = sr * cp * cy - cr * sp * sy;
|
||||
quat.xyz.y = cr * sp * cy + sr * cp * sy;
|
||||
quat.xyz.z = cr * cp * sy - sr * sp * cy;
|
||||
}
|
||||
|
||||
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
|
||||
gyro_bias = bias;
|
||||
}
|
||||
@@ -91,6 +113,19 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
|
||||
rotations += gyro * sample_period;
|
||||
}
|
||||
|
||||
void MotionInput::Calibrate() {
|
||||
calibration_mode = true;
|
||||
calibration_counter = 0;
|
||||
}
|
||||
|
||||
void MotionInput::StopCalibration() {
|
||||
if (calibration_counter++ > CalibrationSamples) {
|
||||
calibration_mode = false;
|
||||
ResetQuaternion();
|
||||
ResetRotations();
|
||||
}
|
||||
}
|
||||
|
||||
// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
|
||||
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
||||
void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||
@@ -222,6 +257,26 @@ Common::Vec3f MotionInput::GetRotations() const {
|
||||
return rotations;
|
||||
}
|
||||
|
||||
Common::Vec3f MotionInput::GetEulerAngles() const {
|
||||
// roll (x-axis rotation)
|
||||
const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
|
||||
const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
|
||||
|
||||
// pitch (y-axis rotation)
|
||||
const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
|
||||
const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
|
||||
|
||||
// yaw (z-axis rotation)
|
||||
const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
|
||||
const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
|
||||
|
||||
return {
|
||||
std::atan2(sinr_cosp, cosr_cosp),
|
||||
2 * std::atan2(sinp, cosp) - Common::PI / 2,
|
||||
std::atan2(siny_cosp, cosy_cosp),
|
||||
};
|
||||
}
|
||||
|
||||
void MotionInput::ResetOrientation() {
|
||||
if (!reset_enabled || only_accelerometer) {
|
||||
return;
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
static constexpr float GyroMaxValue = 5.0f;
|
||||
static constexpr float AccelMaxValue = 7.0f;
|
||||
|
||||
static constexpr std::size_t CalibrationSamples = 300;
|
||||
|
||||
explicit MotionInput();
|
||||
|
||||
MotionInput(const MotionInput&) = default;
|
||||
@@ -35,6 +37,7 @@ public:
|
||||
void SetAcceleration(const Common::Vec3f& acceleration);
|
||||
void SetGyroscope(const Common::Vec3f& gyroscope);
|
||||
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
|
||||
void SetEulerAngles(const Common::Vec3f& euler_angles);
|
||||
void SetGyroBias(const Common::Vec3f& bias);
|
||||
void SetGyroThreshold(f32 threshold);
|
||||
|
||||
@@ -48,17 +51,21 @@ public:
|
||||
void UpdateRotation(u64 elapsed_time);
|
||||
void UpdateOrientation(u64 elapsed_time);
|
||||
|
||||
void Calibrate();
|
||||
|
||||
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
|
||||
[[nodiscard]] Common::Vec3f GetAcceleration() const;
|
||||
[[nodiscard]] Common::Vec3f GetGyroscope() const;
|
||||
[[nodiscard]] Common::Vec3f GetGyroBias() const;
|
||||
[[nodiscard]] Common::Vec3f GetRotations() const;
|
||||
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
|
||||
[[nodiscard]] Common::Vec3f GetEulerAngles() const;
|
||||
|
||||
[[nodiscard]] bool IsMoving(f32 sensitivity) const;
|
||||
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
|
||||
|
||||
private:
|
||||
void StopCalibration();
|
||||
void ResetOrientation();
|
||||
void SetOrientationFromAccelerometer();
|
||||
|
||||
@@ -101,6 +108,12 @@ private:
|
||||
|
||||
// Use accelerometer values to calculate position
|
||||
bool only_accelerometer = true;
|
||||
|
||||
// When enabled it will aggressively adjust for gyro drift
|
||||
bool calibration_mode = false;
|
||||
|
||||
// Used to auto disable calibration mode
|
||||
std::size_t calibration_counter = 0;
|
||||
};
|
||||
|
||||
} // namespace Core::HID
|
||||
|
||||
@@ -35,12 +35,13 @@ namespace {
|
||||
using namespace Common::Literals;
|
||||
|
||||
u32 GetMemorySizeForInit() {
|
||||
return Settings::values.use_extended_memory_layout ? Smc::MemorySize_8GB : Smc::MemorySize_4GB;
|
||||
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
|
||||
: Smc::MemorySize_4GB;
|
||||
}
|
||||
|
||||
Smc::MemoryArrangement GetMemoryArrangeForInit() {
|
||||
return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_8GB
|
||||
: Smc::MemoryArrangement_4GB;
|
||||
return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
|
||||
: Smc::MemoryArrangement_4GB;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -182,8 +182,8 @@ public:
|
||||
explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {}
|
||||
|
||||
static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
|
||||
const u64 lid = lhs.GetId();
|
||||
const u64 rid = rhs.GetId();
|
||||
const uintptr_t lid = reinterpret_cast<uintptr_t>(std::addressof(lhs));
|
||||
const uintptr_t rid = reinterpret_cast<uintptr_t>(std::addressof(rhs));
|
||||
|
||||
if (lid < rid) {
|
||||
return -1;
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> {
|
||||
class KEventInfo : public KSlabAllocated<KEventInfo>,
|
||||
public Common::IntrusiveListBaseNode<KEventInfo> {
|
||||
public:
|
||||
struct InfoCreateThread {
|
||||
u32 thread_id{};
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
@@ -15,13 +16,14 @@ namespace Kernel {
|
||||
|
||||
class KObjectNameGlobalData;
|
||||
|
||||
class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> {
|
||||
class KObjectName : public KSlabAllocated<KObjectName>,
|
||||
public Common::IntrusiveListBaseNode<KObjectName> {
|
||||
public:
|
||||
explicit KObjectName(KernelCore&) {}
|
||||
virtual ~KObjectName() = default;
|
||||
|
||||
static constexpr size_t NameLengthMax = 12;
|
||||
using List = boost::intrusive::list<KObjectName>;
|
||||
using List = Common::IntrusiveListBaseTraits<KObjectName>::ListType;
|
||||
|
||||
static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
|
||||
static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_server_session.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
bool IsSignaled() const override;
|
||||
|
||||
private:
|
||||
using SessionList = boost::intrusive::list<KServerSession>;
|
||||
using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType;
|
||||
|
||||
void CleanupSessions();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_session_request.h"
|
||||
@@ -27,7 +27,7 @@ class KSession;
|
||||
class KThread;
|
||||
|
||||
class KServerSession final : public KSynchronizationObject,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KServerSession> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
|
||||
|
||||
friend class ServiceThread;
|
||||
@@ -67,7 +67,8 @@ private:
|
||||
KSession* m_parent{};
|
||||
|
||||
/// List of threads which are pending a reply.
|
||||
boost::intrusive::list<KSessionRequest> m_request_list{};
|
||||
using RequestList = Common::IntrusiveListBaseTraits<KSessionRequest>::ListType;
|
||||
RequestList m_request_list{};
|
||||
KSessionRequest* m_current_request{};
|
||||
|
||||
KLightLock m_lock;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
@@ -16,7 +18,7 @@ namespace Kernel {
|
||||
|
||||
class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
|
||||
public KAutoObject,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KSessionRequest> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
|
||||
|
||||
public:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Kernel {
|
||||
class KSharedMemory;
|
||||
|
||||
class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
public Common::IntrusiveListBaseNode<KSharedMemoryInfo> {
|
||||
|
||||
public:
|
||||
explicit KSharedMemoryInfo(KernelCore&) {}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "common/spin_lock.h"
|
||||
@@ -119,7 +119,7 @@ s32 GetCurrentCoreId(KernelCore& kernel);
|
||||
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel);
|
||||
|
||||
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
|
||||
public boost::intrusive::list_base_hook<>,
|
||||
public Common::IntrusiveListBaseNode<KThread>,
|
||||
public KTimerTask {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
|
||||
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
public:
|
||||
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
|
||||
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
|
||||
using WaiterList = boost::intrusive::list<KThread>;
|
||||
using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
|
||||
|
||||
/**
|
||||
* Gets the thread's current priority
|
||||
@@ -750,8 +750,9 @@ private:
|
||||
ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
|
||||
|
||||
public:
|
||||
class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>,
|
||||
public boost::intrusive::list_base_hook<> {
|
||||
class LockWithPriorityInheritanceInfo
|
||||
: public KSlabAllocated<LockWithPriorityInheritanceInfo>,
|
||||
public Common::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
|
||||
public:
|
||||
explicit LockWithPriorityInheritanceInfo(KernelCore&) {}
|
||||
|
||||
@@ -839,7 +840,7 @@ public:
|
||||
|
||||
private:
|
||||
using LockWithPriorityInheritanceInfoList =
|
||||
boost::intrusive::list<LockWithPriorityInheritanceInfo>;
|
||||
Common::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
|
||||
|
||||
ConditionVariableThreadTree* m_condvar_tree{};
|
||||
u64 m_condvar_key{};
|
||||
|
||||
@@ -95,7 +95,7 @@ struct KernelCore::Impl {
|
||||
pt_heap_region.GetSize());
|
||||
}
|
||||
|
||||
InitializeHackSharedMemory();
|
||||
InitializeHackSharedMemory(kernel);
|
||||
RegisterHostThread(nullptr);
|
||||
}
|
||||
|
||||
@@ -216,10 +216,12 @@ struct KernelCore::Impl {
|
||||
auto* main_thread{Kernel::KThread::Create(system.Kernel())};
|
||||
main_thread->SetCurrentCore(core);
|
||||
ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess());
|
||||
KThread::Register(system.Kernel(), main_thread);
|
||||
|
||||
auto* idle_thread{Kernel::KThread::Create(system.Kernel())};
|
||||
idle_thread->SetCurrentCore(core);
|
||||
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess());
|
||||
KThread::Register(system.Kernel(), idle_thread);
|
||||
|
||||
schedulers[i]->Initialize(main_thread, idle_thread, core);
|
||||
}
|
||||
@@ -230,6 +232,7 @@ struct KernelCore::Impl {
|
||||
const Core::Timing::CoreTiming& core_timing) {
|
||||
system_resource_limit = KResourceLimit::Create(system.Kernel());
|
||||
system_resource_limit->Initialize(&core_timing);
|
||||
KResourceLimit::Register(kernel, system_resource_limit);
|
||||
|
||||
const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()};
|
||||
const auto total_size{sizes.first};
|
||||
@@ -355,6 +358,7 @@ struct KernelCore::Impl {
|
||||
ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
|
||||
core_id)
|
||||
.IsSuccess());
|
||||
KThread::Register(system.Kernel(), shutdown_threads[core_id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,7 +733,7 @@ struct KernelCore::Impl {
|
||||
memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize());
|
||||
}
|
||||
|
||||
void InitializeHackSharedMemory() {
|
||||
void InitializeHackSharedMemory(KernelCore& kernel) {
|
||||
// Setup memory regions for emulated processes
|
||||
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
|
||||
constexpr std::size_t hid_size{0x40000};
|
||||
@@ -746,14 +750,23 @@ struct KernelCore::Impl {
|
||||
|
||||
hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, hid_size);
|
||||
KSharedMemory::Register(kernel, hid_shared_mem);
|
||||
|
||||
font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, font_size);
|
||||
KSharedMemory::Register(kernel, font_shared_mem);
|
||||
|
||||
irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, irs_size);
|
||||
KSharedMemory::Register(kernel, irs_shared_mem);
|
||||
|
||||
time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, time_size);
|
||||
KSharedMemory::Register(kernel, time_shared_mem);
|
||||
|
||||
hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
|
||||
Svc::MemoryPermission::Read, hidbus_size);
|
||||
KSharedMemory::Register(kernel, hidbus_shared_mem);
|
||||
}
|
||||
|
||||
std::mutex registered_objects_lock;
|
||||
@@ -1072,12 +1085,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
|
||||
// Commit the thread reservation.
|
||||
thread_reservation.Commit();
|
||||
|
||||
// Register the thread.
|
||||
KThread::Register(kernel, thread);
|
||||
|
||||
return std::jthread(
|
||||
[&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
|
||||
// Set the thread name.
|
||||
Common::SetCurrentThreadName(thread_name.c_str());
|
||||
|
||||
// Register the thread.
|
||||
// Set the thread as current.
|
||||
kernel.RegisterHostThread(thread);
|
||||
|
||||
// Run the callback.
|
||||
@@ -1099,6 +1115,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
|
||||
// Ensure that we don't hold onto any extra references.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
|
||||
// Register the new process.
|
||||
KProcess::Register(*this, process);
|
||||
|
||||
// Run the host thread.
|
||||
return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func));
|
||||
}
|
||||
@@ -1124,6 +1143,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
|
||||
// Ensure that we don't hold onto any extra references.
|
||||
SCOPE_EXIT({ process->Close(); });
|
||||
|
||||
// Register the new process.
|
||||
KProcess::Register(*this, process);
|
||||
|
||||
// Reserve a new thread from the process resource limit.
|
||||
KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
|
||||
ASSERT(thread_reservation.Succeeded());
|
||||
@@ -1136,6 +1158,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
|
||||
// Commit the thread reservation.
|
||||
thread_reservation.Commit();
|
||||
|
||||
// Register the new thread.
|
||||
KThread::Register(*this, thread);
|
||||
|
||||
// Begin running the thread.
|
||||
ASSERT(R_SUCCEEDED(thread->Run()));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
@@ -1335,7 +1336,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
|
||||
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
|
||||
{27, nullptr, "CreateCacheStorage"},
|
||||
{27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
|
||||
{28, nullptr, "GetSaveDataSizeMax"},
|
||||
{29, nullptr, "GetCacheStorageMax"},
|
||||
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
@@ -1738,6 +1739,36 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
|
||||
rb.Push(size.journal);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u16 index;
|
||||
s64 size;
|
||||
s64 journal_size;
|
||||
};
|
||||
static_assert(sizeof(InputParameters) == 24);
|
||||
|
||||
struct OutputParameters {
|
||||
u32 storage_target;
|
||||
u64 required_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 16);
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto params = rp.PopRaw<InputParameters>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
|
||||
params.index, params.size, params.journal_size);
|
||||
|
||||
const OutputParameters resp{
|
||||
.storage_target = 1,
|
||||
.required_size = 0,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(resp);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -1807,7 +1838,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestCon
|
||||
}
|
||||
|
||||
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(AM::ResultNoDataInChannel);
|
||||
|
||||
@@ -333,6 +333,7 @@ private:
|
||||
void GetPseudoDeviceId(HLERequestContext& ctx);
|
||||
void ExtendSaveData(HLERequestContext& ctx);
|
||||
void GetSaveDataSize(HLERequestContext& ctx);
|
||||
void CreateCacheStorage(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
|
||||
void BeginBlockingHomeButton(HLERequestContext& ctx);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/mii/mii_manager.h"
|
||||
#include "core/hle/service/nfp/nfp_device.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
@@ -72,10 +72,10 @@ void Cabinet::Execute() {
|
||||
|
||||
// TODO: listen on all controllers
|
||||
if (nfp_device == nullptr) {
|
||||
nfp_device = std::make_shared<Service::NFP::NfpDevice>(
|
||||
nfp_device = std::make_shared<Service::NFC::NfcDevice>(
|
||||
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
|
||||
nfp_device->Initialize();
|
||||
nfp_device->StartDetection(Service::NFP::TagProtocol::All);
|
||||
nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
|
||||
}
|
||||
|
||||
const Core::Frontend::CabinetParameters parameters{
|
||||
@@ -106,20 +106,22 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
|
||||
Cancel();
|
||||
}
|
||||
|
||||
if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
|
||||
nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
|
||||
if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
|
||||
nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
|
||||
Cancel();
|
||||
}
|
||||
|
||||
if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
|
||||
nfp_device->Mount(Service::NFP::MountTarget::All);
|
||||
if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) {
|
||||
nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
|
||||
}
|
||||
|
||||
switch (applet_input_common.applet_mode) {
|
||||
case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
|
||||
Service::NFP::AmiiboName name{};
|
||||
std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
|
||||
nfp_device->SetRegisterInfoPrivate(name);
|
||||
Service::NFP::RegisterInfoPrivate register_info{};
|
||||
std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(),
|
||||
std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1));
|
||||
|
||||
nfp_device->SetRegisterInfoPrivate(register_info);
|
||||
break;
|
||||
}
|
||||
case Service::NFP::CabinetMode::StartGameDataEraser:
|
||||
@@ -139,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
|
||||
applet_output.device_handle = applet_input_common.device_handle;
|
||||
applet_output.result = CabinetResult::Cancel;
|
||||
const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
|
||||
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
|
||||
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false);
|
||||
nfp_device->Finalize();
|
||||
|
||||
if (reg_result.IsSuccess()) {
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Service::NFP {
|
||||
class NfpDevice;
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
}
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
Core::System& system;
|
||||
|
||||
bool is_complete{false};
|
||||
std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
|
||||
std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
|
||||
Kernel::KEvent* availability_change_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
StartParamForAmiiboSettings applet_input_common{};
|
||||
|
||||
@@ -49,12 +49,6 @@ public:
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
if (impl->GetSystem()
|
||||
.Initialize(device_name, in_params, handle, applet_resource_user_id)
|
||||
.IsError()) {
|
||||
LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
|
||||
}
|
||||
}
|
||||
|
||||
~IAudioOut() override {
|
||||
@@ -287,6 +281,14 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
|
||||
|
||||
auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
|
||||
in_params, handle, applet_resource_user_id);
|
||||
result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle,
|
||||
applet_resource_user_id);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
impl->sessions[new_session_id] = audio_out->GetImpl();
|
||||
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
@@ -552,9 +554,9 @@ public:
|
||||
// Write the data to memory
|
||||
ctx.WriteBuffer(begin, range_size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(actual_entries));
|
||||
rb.Push<u64>(actual_entries);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -712,7 +714,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
|
||||
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
|
||||
{60, nullptr, "OpenSaveDataInfoReader"},
|
||||
{61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
|
||||
{62, nullptr, "OpenCacheStorageList"},
|
||||
{62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
|
||||
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
|
||||
{65, nullptr, "UpdateSaveDataMacForDebug"},
|
||||
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
|
||||
@@ -921,6 +923,15 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
|
||||
std::make_shared<ISaveDataInfoReader>(system, space, fsc));
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
|
||||
fsc);
|
||||
}
|
||||
|
||||
void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called.");
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ private:
|
||||
void OpenSaveDataFileSystem(HLERequestContext& ctx);
|
||||
void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
|
||||
void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
|
||||
void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
|
||||
void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
|
||||
void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
|
||||
void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
|
||||
|
||||
@@ -423,8 +423,8 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is unique to yuzu for the turbo buttons to work properly
|
||||
controller.device->TurboButtonUpdate();
|
||||
// This function is unique to yuzu for the turbo buttons and motion to work properly
|
||||
controller.device->StatusUpdate();
|
||||
|
||||
auto& pad_entry = controller.npad_pad_state;
|
||||
auto& trigger_entry = controller.npad_trigger_state;
|
||||
@@ -979,8 +979,8 @@ void Controller_NPad::VibrateController(
|
||||
}
|
||||
|
||||
void Controller_NPad::VibrateControllers(
|
||||
const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
|
||||
const std::vector<Core::HID::VibrationValue>& vibration_values) {
|
||||
std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
|
||||
std::span<const Core::HID::VibrationValue> vibration_values) {
|
||||
if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ public:
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
|
||||
void VibrateControllers(
|
||||
const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
|
||||
const std::vector<Core::HID::VibrationValue>& vibration_values);
|
||||
std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
|
||||
std::span<const Core::HID::VibrationValue> vibration_values);
|
||||
|
||||
Core::HID::VibrationValue GetLastVibration(
|
||||
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
|
||||
|
||||
@@ -1601,16 +1601,16 @@ void Hid::SendVibrationValues(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
const auto handles = ctx.ReadBuffer(0);
|
||||
const auto vibrations = ctx.ReadBuffer(1);
|
||||
const auto handle_data = ctx.ReadBuffer(0);
|
||||
const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
|
||||
const auto vibration_data = ctx.ReadBuffer(1);
|
||||
const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
|
||||
|
||||
std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles(
|
||||
handles.size() / sizeof(Core::HID::VibrationDeviceHandle));
|
||||
std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() /
|
||||
sizeof(Core::HID::VibrationValue));
|
||||
|
||||
std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
|
||||
std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
|
||||
auto vibration_device_handles =
|
||||
std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
|
||||
handle_count);
|
||||
auto vibration_values = std::span(
|
||||
reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.VibrateControllers(vibration_device_handles, vibration_values);
|
||||
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
|
||||
auto* session = Kernel::KSession::Create(kernel);
|
||||
session->Initialize(nullptr, 0);
|
||||
Kernel::KSession::Register(kernel, session);
|
||||
|
||||
auto next_manager = std::make_shared<Service::SessionRequestManager>(
|
||||
kernel, manager->GetServerManager());
|
||||
|
||||
@@ -25,6 +25,9 @@ ServiceContext::ServiceContext(Core::System& system_, std::string name_)
|
||||
Kernel::KProcess::ProcessType::KernelInternal,
|
||||
kernel.GetSystemResourceLimit())
|
||||
.IsSuccess());
|
||||
|
||||
// Register the process.
|
||||
Kernel::KProcess::Register(kernel, process);
|
||||
process_created = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ Mutex::Mutex(Core::System& system) : m_system(system) {
|
||||
m_event = Kernel::KEvent::Create(system.Kernel());
|
||||
m_event->Initialize(nullptr);
|
||||
|
||||
// Register the event.
|
||||
Kernel::KEvent::Register(system.Kernel(), m_event);
|
||||
|
||||
ASSERT(R_SUCCEEDED(m_event->Signal()));
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nfp/amiibo_crypto.h"
|
||||
#include "core/hle/service/nfc/common/amiibo_crypto.h"
|
||||
|
||||
namespace Service::NFP::AmiiboCrypto {
|
||||
|
||||
@@ -55,7 +55,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
|
||||
if (amiibo_data.constant_value != 0xA5) {
|
||||
return false;
|
||||
}
|
||||
if (amiibo_data.model_info.tag_type != PackedTagType::Type2) {
|
||||
if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
|
||||
return false;
|
||||
}
|
||||
if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {
|
||||
+2
-2
@@ -24,9 +24,9 @@ using DrgbOutput = std::array<u8, 0x20>;
|
||||
struct HashSeed {
|
||||
u16_be magic;
|
||||
std::array<u8, 0xE> padding;
|
||||
UniqueSerialNumber uid_1;
|
||||
NFC::UniqueSerialNumber uid_1;
|
||||
u8 nintendo_id_1;
|
||||
UniqueSerialNumber uid_2;
|
||||
NFC::UniqueSerialNumber uid_2;
|
||||
u8 nintendo_id_2;
|
||||
std::array<u8, 0x20> keygen_salt;
|
||||
};
|
||||
+424
-295
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_types.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
enum class ControllerTriggerType;
|
||||
enum class NpadIdType : u32;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice {
|
||||
public:
|
||||
NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_,
|
||||
Kernel::KEvent* availability_change_event_);
|
||||
~NfcDevice();
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
Result StartDetection(NfcProtocol allowed_protocol);
|
||||
Result StopDetection();
|
||||
|
||||
Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
|
||||
|
||||
Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
|
||||
std::span<MifareReadBlockData> read_block_data) const;
|
||||
Result ReadMifare(const MifareReadBlockParameter& parameter,
|
||||
MifareReadBlockData& read_block_data) const;
|
||||
|
||||
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
|
||||
Result WriteMifare(const MifareWriteBlockParameter& parameter);
|
||||
|
||||
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data, std::span<u8> out_data);
|
||||
|
||||
Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
|
||||
Result Unmount();
|
||||
|
||||
Result Flush();
|
||||
Result FlushDebug();
|
||||
Result FlushWithBreak(NFP::BreakType break_type);
|
||||
Result Restore();
|
||||
|
||||
Result GetCommonInfo(NFP::CommonInfo& common_info) const;
|
||||
Result GetModelInfo(NFP::ModelInfo& model_info) const;
|
||||
Result GetRegisterInfo(NFP::RegisterInfo& register_info) const;
|
||||
Result GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const;
|
||||
Result GetAdminInfo(NFP::AdminInfo& admin_info) const;
|
||||
|
||||
Result DeleteRegisterInfo();
|
||||
Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
|
||||
Result RestoreAmiibo();
|
||||
Result Format();
|
||||
|
||||
Result OpenApplicationArea(u32 access_id);
|
||||
Result GetApplicationAreaId(u32& application_area_id) const;
|
||||
Result GetApplicationArea(std::span<u8> data) const;
|
||||
Result SetApplicationArea(std::span<const u8> data);
|
||||
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
|
||||
Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
|
||||
Result DeleteApplicationArea();
|
||||
Result ExistsApplicationArea(bool& has_application_area) const;
|
||||
|
||||
Result GetAll(NFP::NfpData& data) const;
|
||||
Result SetAll(const NFP::NfpData& data);
|
||||
Result BreakTag(NFP::BreakType break_type);
|
||||
Result ReadBackupData(std::span<u8> data) const;
|
||||
Result WriteBackupData(std::span<const u8> data);
|
||||
Result WriteNtf(std::span<const u8> data);
|
||||
|
||||
u64 GetHandle() const;
|
||||
DeviceState GetCurrentState() const;
|
||||
Result GetNpadId(Core::HID::NpadIdType& out_npad_id) const;
|
||||
|
||||
Kernel::KReadableEvent& GetActivateEvent() const;
|
||||
Kernel::KReadableEvent& GetDeactivateEvent() const;
|
||||
|
||||
private:
|
||||
void NpadUpdate(Core::HID::ControllerTriggerType type);
|
||||
bool LoadNfcTag(std::span<const u8> data);
|
||||
void CloseNfcTag();
|
||||
|
||||
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
|
||||
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
|
||||
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
|
||||
u64 GetCurrentPosixTime() const;
|
||||
u64 RemoveVersionByte(u64 application_id) const;
|
||||
void UpdateSettingsCrc();
|
||||
void UpdateRegisterInfoCrc();
|
||||
|
||||
bool is_controller_set{};
|
||||
int callback_key;
|
||||
const Core::HID::NpadIdType npad_id;
|
||||
Core::System& system;
|
||||
Core::HID::EmulatedController* npad_device = nullptr;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
Kernel::KEvent* activate_event = nullptr;
|
||||
Kernel::KEvent* deactivate_event = nullptr;
|
||||
Kernel::KEvent* availability_change_event = nullptr;
|
||||
|
||||
bool is_initalized{};
|
||||
NfcProtocol allowed_protocols{};
|
||||
DeviceState device_state{DeviceState::Unavailable};
|
||||
|
||||
// NFP data
|
||||
bool is_data_moddified{};
|
||||
bool is_app_area_open{};
|
||||
bool is_plain_amiibo{};
|
||||
NFP::MountTarget mount_target{NFP::MountTarget::None};
|
||||
|
||||
NFP::NTAG215File tag_data{};
|
||||
std::vector<u8> mifare_data{};
|
||||
NFP::EncryptedNTAG215File encrypted_tag_data{};
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -0,0 +1,695 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/nfc/common/device_manager.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
|
||||
: system{system_}, service_context{service_context_} {
|
||||
|
||||
availability_change_event =
|
||||
service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
|
||||
|
||||
for (u32 device_index = 0; device_index < devices.size(); device_index++) {
|
||||
devices[device_index] =
|
||||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
|
||||
service_context, availability_change_event);
|
||||
}
|
||||
|
||||
is_initialized = false;
|
||||
}
|
||||
|
||||
DeviceManager ::~DeviceManager() {
|
||||
service_context.CloseEvent(availability_change_event);
|
||||
}
|
||||
|
||||
Result DeviceManager::Initialize() {
|
||||
for (auto& device : devices) {
|
||||
device->Initialize();
|
||||
}
|
||||
is_initialized = true;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DeviceManager::Finalize() {
|
||||
for (auto& device : devices) {
|
||||
device->Finalize();
|
||||
}
|
||||
is_initialized = false;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
|
||||
std::size_t max_allowed_devices) const {
|
||||
for (auto& device : devices) {
|
||||
if (nfp_devices.size() >= max_allowed_devices) {
|
||||
continue;
|
||||
}
|
||||
if (device->GetCurrentState() != DeviceState::Unavailable) {
|
||||
nfp_devices.push_back(device->GetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
if (nfp_devices.empty()) {
|
||||
return ResultDeviceNotFound;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
const auto result = GetDeviceFromHandle(device_handle, device, false);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
return device->GetCurrentState();
|
||||
}
|
||||
|
||||
return DeviceState::Unavailable;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetNpadId(npad_id);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
|
||||
return availability_change_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->StartDetection(tag_protocol);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::StopDetection(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->StopDetection();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetTagInfo(tag_info, is_mifare);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
GetDeviceFromHandle(device_handle, device, false);
|
||||
|
||||
// TODO: Return proper error code on failure
|
||||
return device->GetActivateEvent();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
GetDeviceFromHandle(device_handle, device, false);
|
||||
|
||||
// TODO: Return proper error code on failure
|
||||
return device->GetDeactivateEvent();
|
||||
}
|
||||
|
||||
Result DeviceManager::ReadMifare(u64 device_handle,
|
||||
std::span<const MifareReadBlockParameter> read_parameters,
|
||||
std::span<MifareReadBlockData> read_data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->ReadMifare(read_parameters, read_data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::WriteMifare(u64 device_handle,
|
||||
std::span<const MifareWriteBlockParameter> write_parameters) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->WriteMifare(write_parameters);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
|
||||
const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data,
|
||||
std::span<u8> out_data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->SendCommandByPassThrough(timeout, command_data, out_data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
|
||||
NFP::MountTarget mount_target) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->Mount(model_type, mount_target);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::Unmount(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->Unmount();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->OpenApplicationArea(access_id);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetApplicationArea(data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->SetApplicationArea(data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::Flush(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->Flush();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::Restore(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->Restore();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
|
||||
std::span<const u8> data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->CreateApplicationArea(access_id, data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetRegisterInfo(register_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetCommonInfo(common_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetModelInfo(model_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 DeviceManager::GetApplicationAreaSize() const {
|
||||
return sizeof(NFP::ApplicationArea);
|
||||
}
|
||||
|
||||
Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
|
||||
std::span<const u8> data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->RecreateApplicationArea(access_id, data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::Format(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->Format();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetAdminInfo(admin_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
|
||||
NFP::RegisterInfoPrivate& register_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetRegisterInfoPrivate(register_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
|
||||
const NFP::RegisterInfoPrivate& register_info) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->SetRegisterInfoPrivate(register_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->DeleteRegisterInfo();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->DeleteApplicationArea();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->ExistsApplicationArea(has_application_area);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetAll(nfp_data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->SetAll(nfp_data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::FlushDebug(u64 device_handle) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->FlushDebug();
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->BreakTag(break_type);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->ReadBackupData(data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->WriteBackupData(data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->WriteNtf(data);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
|
||||
bool check_state) const {
|
||||
if (check_state) {
|
||||
const Result is_parameter_set = IsNfcParameterSet();
|
||||
if (is_parameter_set.IsError()) {
|
||||
return is_parameter_set;
|
||||
}
|
||||
const Result is_enabled = IsNfcEnabled();
|
||||
if (is_enabled.IsError()) {
|
||||
return is_enabled;
|
||||
}
|
||||
const Result is_nfc_initialized = IsNfcInitialized();
|
||||
if (is_nfc_initialized.IsError()) {
|
||||
return is_nfc_initialized;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
nfc_device = device;
|
||||
return ResultSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultDeviceNotFound;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
|
||||
const auto result = GetDeviceFromHandle(handle, device, true);
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
return CheckDeviceState(device);
|
||||
}
|
||||
|
||||
Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
|
||||
Result operation_result) const {
|
||||
if (operation_result.IsSuccess()) {
|
||||
return operation_result;
|
||||
}
|
||||
|
||||
const Result is_parameter_set = IsNfcParameterSet();
|
||||
if (is_parameter_set.IsError()) {
|
||||
return is_parameter_set;
|
||||
}
|
||||
const Result is_enabled = IsNfcEnabled();
|
||||
if (is_enabled.IsError()) {
|
||||
return is_enabled;
|
||||
}
|
||||
const Result is_nfc_initialized = IsNfcInitialized();
|
||||
if (is_nfc_initialized.IsError()) {
|
||||
return is_nfc_initialized;
|
||||
}
|
||||
const Result device_state = CheckDeviceState(device);
|
||||
if (device_state.IsError()) {
|
||||
return device_state;
|
||||
}
|
||||
|
||||
return operation_result;
|
||||
}
|
||||
|
||||
Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
|
||||
if (device == nullptr) {
|
||||
return ResultInvalidArgument;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DeviceManager::IsNfcEnabled() const {
|
||||
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
|
||||
const bool is_enabled = true;
|
||||
if (!is_enabled) {
|
||||
return ResultNfcDisabled;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DeviceManager::IsNfcParameterSet() const {
|
||||
// TODO: This calls checks against a bool on offset 0x450
|
||||
const bool is_set = true;
|
||||
if (!is_set) {
|
||||
return ResultUnknown76;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DeviceManager::IsNfcInitialized() const {
|
||||
if (!is_initialized) {
|
||||
return ResultNfcNotInitialized;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -0,0 +1,100 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_types.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
|
||||
class DeviceManager {
|
||||
public:
|
||||
explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
|
||||
~DeviceManager();
|
||||
|
||||
// Nfc device manager
|
||||
Result Initialize();
|
||||
Result Finalize();
|
||||
Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
|
||||
DeviceState GetDeviceState(u64 device_handle) const;
|
||||
Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
|
||||
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
|
||||
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
|
||||
Result StopDetection(u64 device_handle);
|
||||
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
|
||||
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
|
||||
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
|
||||
Result ReadMifare(u64 device_handle,
|
||||
const std::span<const MifareReadBlockParameter> read_parameters,
|
||||
std::span<MifareReadBlockData> read_data);
|
||||
Result WriteMifare(u64 device_handle,
|
||||
std::span<const MifareWriteBlockParameter> write_parameters);
|
||||
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data, std::span<u8> out_data);
|
||||
|
||||
// Nfp device manager
|
||||
Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
|
||||
Result Unmount(u64 device_handle);
|
||||
Result OpenApplicationArea(u64 device_handle, u32 access_id);
|
||||
Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
|
||||
Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
|
||||
Result Flush(u64 device_handle);
|
||||
Result Restore(u64 device_handle);
|
||||
Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
|
||||
Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
|
||||
Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
|
||||
Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
|
||||
u32 GetApplicationAreaSize() const;
|
||||
Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
|
||||
Result Format(u64 device_handle);
|
||||
Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
|
||||
Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
|
||||
Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
|
||||
Result DeleteRegisterInfo(u64 device_handle);
|
||||
Result DeleteApplicationArea(u64 device_handle);
|
||||
Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
|
||||
Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
|
||||
Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
|
||||
Result FlushDebug(u64 device_handle);
|
||||
Result BreakTag(u64 device_handle, NFP::BreakType break_type);
|
||||
Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
|
||||
Result WriteBackupData(u64 device_handle, std::span<const u8> data);
|
||||
Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
|
||||
|
||||
private:
|
||||
Result IsNfcEnabled() const;
|
||||
Result IsNfcParameterSet() const;
|
||||
Result IsNfcInitialized() const;
|
||||
|
||||
Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
|
||||
bool check_state) const;
|
||||
|
||||
Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
|
||||
Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
|
||||
Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
|
||||
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
|
||||
|
||||
bool is_initialized = false;
|
||||
mutable std::mutex mutex;
|
||||
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
|
||||
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* availability_change_event;
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::NFC::Mifare {
|
||||
|
||||
constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64);
|
||||
constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
|
||||
constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
|
||||
constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
|
||||
constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
|
||||
constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
|
||||
|
||||
} // namespace Service::NFC::Mifare
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
enum class MifareCmd : u8 {
|
||||
AuthA = 0x60,
|
||||
AuthB = 0x61,
|
||||
Read = 0x30,
|
||||
Write = 0xA0,
|
||||
Transfer = 0xB0,
|
||||
Decrement = 0xC0,
|
||||
Increment = 0xC1,
|
||||
Store = 0xC2
|
||||
};
|
||||
|
||||
using DataBlock = std::array<u8, 0x10>;
|
||||
using KeyData = std::array<u8, 0x6>;
|
||||
|
||||
struct SectorKey {
|
||||
MifareCmd command;
|
||||
u8 unknown; // Usually 1
|
||||
INSERT_PADDING_BYTES(0x6);
|
||||
KeyData sector_key;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
|
||||
|
||||
// This is nn::nfc::MifareReadBlockParameter
|
||||
struct MifareReadBlockParameter {
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
|
||||
"MifareReadBlockParameter is an invalid size");
|
||||
|
||||
// This is nn::nfc::MifareReadBlockData
|
||||
struct MifareReadBlockData {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
|
||||
|
||||
// This is nn::nfc::MifareWriteBlockParameter
|
||||
struct MifareWriteBlockParameter {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
|
||||
"MifareWriteBlockParameter is an invalid size");
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -1,400 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_user.h"
|
||||
#include "core/hle/service/nfc/nfc_device.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
MFIUser::MFIUser(Core::System& system_)
|
||||
: ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &MFIUser::Initialize, "Initialize"},
|
||||
{1, &MFIUser::Finalize, "Finalize"},
|
||||
{2, &MFIUser::ListDevices, "ListDevices"},
|
||||
{3, &MFIUser::StartDetection, "StartDetection"},
|
||||
{4, &MFIUser::StopDetection, "StopDetection"},
|
||||
{5, &MFIUser::Read, "Read"},
|
||||
{6, &MFIUser::Write, "Write"},
|
||||
{7, &MFIUser::GetTagInfo, "GetTagInfo"},
|
||||
{8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
|
||||
{9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
|
||||
{10, &MFIUser::GetState, "GetState"},
|
||||
{11, &MFIUser::GetDeviceState, "GetDeviceState"},
|
||||
{12, &MFIUser::GetNpadId, "GetNpadId"},
|
||||
{13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent");
|
||||
|
||||
for (u32 device_index = 0; device_index < 10; device_index++) {
|
||||
devices[device_index] =
|
||||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
|
||||
service_context, availability_change_event);
|
||||
}
|
||||
}
|
||||
|
||||
MFIUser ::~MFIUser() {
|
||||
availability_change_event->Close();
|
||||
}
|
||||
|
||||
void MFIUser::Initialize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::Initialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Initialize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void MFIUser::Finalize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::NonInitialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Finalize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void MFIUser::ListDevices(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWriteBuffer()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareInvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.GetWriteBufferSize() == 0) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareInvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u64> nfp_devices;
|
||||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
|
||||
|
||||
for (const auto& device : devices) {
|
||||
if (nfp_devices.size() >= max_allowed_devices) {
|
||||
continue;
|
||||
}
|
||||
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
|
||||
nfp_devices.push_back(device->GetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
if (nfp_devices.empty()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(nfp_devices);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<s32>(nfp_devices.size()));
|
||||
}
|
||||
|
||||
void MFIUser::StartDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::StopDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StopDetection();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::Read(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
|
||||
std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
|
||||
|
||||
memcpy(read_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(NFP::MifareReadBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
|
||||
for (std::size_t i = 0; i < number_of_commands; i++) {
|
||||
result = device.value()->MifareRead(read_commands[i], out_data[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(out_data);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::Write(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
|
||||
std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
|
||||
|
||||
memcpy(write_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
|
||||
for (std::size_t i = 0; i < number_of_commands; i++) {
|
||||
result = device.value()->MifareWrite(write_commands[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device.value()->Flush();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::GetTagInfo(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
NFP::TagInfo tag_info{};
|
||||
const auto result = device.value()->GetTagInfo(tag_info, true);
|
||||
ctx.WriteBuffer(tag_info);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void MFIUser::GetActivateEventHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetActivateEvent());
|
||||
}
|
||||
|
||||
void MFIUser::GetDeactivateEventHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetDeactivateEvent());
|
||||
}
|
||||
|
||||
void MFIUser::GetState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(state);
|
||||
}
|
||||
|
||||
void MFIUser::GetDeviceState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetCurrentState());
|
||||
}
|
||||
|
||||
void MFIUser::GetNpadId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareDeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetNpadId());
|
||||
}
|
||||
|
||||
void MFIUser::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(MifareNfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(availability_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) {
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -1,52 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
|
||||
class MFIUser final : public ServiceFramework<MFIUser> {
|
||||
public:
|
||||
explicit MFIUser(Core::System& system_);
|
||||
~MFIUser();
|
||||
|
||||
private:
|
||||
enum class State : u32 {
|
||||
NonInitialized,
|
||||
Initialized,
|
||||
};
|
||||
|
||||
void Initialize(HLERequestContext& ctx);
|
||||
void Finalize(HLERequestContext& ctx);
|
||||
void ListDevices(HLERequestContext& ctx);
|
||||
void StartDetection(HLERequestContext& ctx);
|
||||
void StopDetection(HLERequestContext& ctx);
|
||||
void Read(HLERequestContext& ctx);
|
||||
void Write(HLERequestContext& ctx);
|
||||
void GetTagInfo(HLERequestContext& ctx);
|
||||
void GetActivateEventHandle(HLERequestContext& ctx);
|
||||
void GetDeactivateEventHandle(HLERequestContext& ctx);
|
||||
void GetState(HLERequestContext& ctx);
|
||||
void GetDeviceState(HLERequestContext& ctx);
|
||||
void GetNpadId(HLERequestContext& ctx);
|
||||
void GetAvailabilityChangeEventHandle(HLERequestContext& ctx);
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
|
||||
|
||||
State state{State::NonInitialized};
|
||||
Kernel::KEvent* availability_change_event;
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -6,14 +6,115 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/mifare_user.h"
|
||||
#include "core/hle/service/nfc/nfc.h"
|
||||
#include "core/hle/service/nfc/nfc_user.h"
|
||||
#include "core/hle/service/nfc/nfc_interface.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
class IUser final : public NfcInterface {
|
||||
public:
|
||||
explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NfcInterface::Initialize, "InitializeOld"},
|
||||
{1, &NfcInterface::Finalize, "FinalizeOld"},
|
||||
{2, &NfcInterface::GetState, "GetStateOld"},
|
||||
{3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
|
||||
{400, &NfcInterface::Initialize, "Initialize"},
|
||||
{401, &NfcInterface::Finalize, "Finalize"},
|
||||
{402, &NfcInterface::GetState, "GetState"},
|
||||
{403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
|
||||
{404, &NfcInterface::ListDevices, "ListDevices"},
|
||||
{405, &NfcInterface::GetDeviceState, "GetDeviceState"},
|
||||
{406, &NfcInterface::GetNpadId, "GetNpadId"},
|
||||
{407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||
{408, &NfcInterface::StartDetection, "StartDetection"},
|
||||
{409, &NfcInterface::StopDetection, "StopDetection"},
|
||||
{410, &NfcInterface::GetTagInfo, "GetTagInfo"},
|
||||
{411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
|
||||
{412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
|
||||
{1000, &NfcInterface::ReadMifare, "ReadMifare"},
|
||||
{1001, &NfcInterface::WriteMifare ,"WriteMifare"},
|
||||
{1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
|
||||
{1301, nullptr, "KeepPassThroughSession"},
|
||||
{1302, nullptr, "ReleasePassThroughSession"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class ISystem final : public NfcInterface {
|
||||
public:
|
||||
explicit ISystem(Core::System& system_)
|
||||
: NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NfcInterface::Initialize, "InitializeOld"},
|
||||
{1, &NfcInterface::Finalize, "FinalizeOld"},
|
||||
{2, &NfcInterface::GetState, "GetStateOld"},
|
||||
{3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
|
||||
{100, nullptr, "SetNfcEnabledOld"},
|
||||
{400, &NfcInterface::Initialize, "Initialize"},
|
||||
{401, &NfcInterface::Finalize, "Finalize"},
|
||||
{402, &NfcInterface::GetState, "GetState"},
|
||||
{403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
|
||||
{404, &NfcInterface::ListDevices, "ListDevices"},
|
||||
{405, &NfcInterface::GetDeviceState, "GetDeviceState"},
|
||||
{406, &NfcInterface::GetNpadId, "GetNpadId"},
|
||||
{407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||
{408, &NfcInterface::StartDetection, "StartDetection"},
|
||||
{409, &NfcInterface::StopDetection, "StopDetection"},
|
||||
{410, &NfcInterface::GetTagInfo, "GetTagInfo"},
|
||||
{411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
|
||||
{412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
|
||||
{500, nullptr, "SetNfcEnabled"},
|
||||
{510, nullptr, "OutputTestWave"},
|
||||
{1000, &NfcInterface::ReadMifare, "ReadMifare"},
|
||||
{1001, &NfcInterface::WriteMifare, "WriteMifare"},
|
||||
{1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
|
||||
{1301, nullptr, "KeepPassThroughSession"},
|
||||
{1302, nullptr, "ReleasePassThroughSession"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
// MFInterface has an unique interface but it's identical to NfcInterface so we can keep the code
|
||||
// simpler
|
||||
using MFInterface = NfcInterface;
|
||||
class MFIUser final : public MFInterface {
|
||||
public:
|
||||
explicit MFIUser(Core::System& system_)
|
||||
: MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
|
||||
// clang-format off
|
||||
static const FunctionInfoTyped<MFIUser> functions[] = {
|
||||
{0, &MFIUser::Initialize, "Initialize"},
|
||||
{1, &MFIUser::Finalize, "Finalize"},
|
||||
{2, &MFIUser::ListDevices, "ListDevices"},
|
||||
{3, &MFIUser::StartDetection, "StartDetection"},
|
||||
{4, &MFIUser::StopDetection, "StopDetection"},
|
||||
{5, &MFIUser::ReadMifare, "Read"},
|
||||
{6, &MFIUser::WriteMifare, "Write"},
|
||||
{7, &MFIUser::GetTagInfo, "GetTagInfo"},
|
||||
{8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
|
||||
{9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
|
||||
{10, &MFIUser::GetState, "GetState"},
|
||||
{11, &MFIUser::GetDeviceState, "GetDeviceState"},
|
||||
{12, &MFIUser::GetNpadId, "GetNpadId"},
|
||||
{13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class IAm final : public ServiceFramework<IAm> {
|
||||
public:
|
||||
explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
|
||||
@@ -34,7 +135,7 @@ public:
|
||||
explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
|
||||
{0, &NFC_AM::CreateAmNfcInterface, "CreateAmNfcInterface"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -42,7 +143,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateAmInterface(HLERequestContext& ctx) {
|
||||
void CreateAmNfcInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -56,7 +157,7 @@ public:
|
||||
explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
|
||||
{0, &NFC_MF_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -64,7 +165,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateUserInterface(HLERequestContext& ctx) {
|
||||
void CreateUserNfcInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -78,7 +179,7 @@ public:
|
||||
explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
|
||||
{0, &NFC_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -86,7 +187,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateUserInterface(HLERequestContext& ctx) {
|
||||
void CreateUserNfcInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -95,49 +196,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class ISystem final : public ServiceFramework<ISystem> {
|
||||
public:
|
||||
explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Initialize"},
|
||||
{1, nullptr, "Finalize"},
|
||||
{2, nullptr, "GetStateOld"},
|
||||
{3, nullptr, "IsNfcEnabledOld"},
|
||||
{100, nullptr, "SetNfcEnabledOld"},
|
||||
{400, nullptr, "InitializeSystem"},
|
||||
{401, nullptr, "FinalizeSystem"},
|
||||
{402, nullptr, "GetState"},
|
||||
{403, nullptr, "IsNfcEnabled"},
|
||||
{404, nullptr, "ListDevices"},
|
||||
{405, nullptr, "GetDeviceState"},
|
||||
{406, nullptr, "GetNpadId"},
|
||||
{407, nullptr, "AttachAvailabilityChangeEvent"},
|
||||
{408, nullptr, "StartDetection"},
|
||||
{409, nullptr, "StopDetection"},
|
||||
{410, nullptr, "GetTagInfo"},
|
||||
{411, nullptr, "AttachActivateEvent"},
|
||||
{412, nullptr, "AttachDeactivateEvent"},
|
||||
{500, nullptr, "SetNfcEnabled"},
|
||||
{510, nullptr, "OutputTestWave"},
|
||||
{1000, nullptr, "ReadMifare"},
|
||||
{1001, nullptr, "WriteMifare"},
|
||||
{1300, nullptr, "SendCommandByPassThrough"},
|
||||
{1301, nullptr, "KeepPassThroughSession"},
|
||||
{1302, nullptr, "ReleasePassThroughSession"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
class NFC_SYS final : public ServiceFramework<NFC_SYS> {
|
||||
public:
|
||||
explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
|
||||
{0, &NFC_SYS::CreateSystemNfcInterface, "CreateSystemNfcInterface"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -145,7 +209,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateSystemInterface(HLERequestContext& ctx) {
|
||||
void CreateSystemNfcInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -161,6 +225,7 @@ void LoopProcess(Core::System& system) {
|
||||
server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system));
|
||||
server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system));
|
||||
server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system));
|
||||
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/input.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/nfc_device.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/nfc/nfc_user.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_,
|
||||
Kernel::KEvent* availability_change_event_)
|
||||
: npad_id{npad_id_}, system{system_}, service_context{service_context_},
|
||||
availability_change_event{availability_change_event_} {
|
||||
activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
|
||||
deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
|
||||
npad_device = system.HIDCore().GetEmulatedController(npad_id);
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
|
||||
.is_npad_service = false,
|
||||
};
|
||||
is_controller_set = true;
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
||||
NfcDevice::~NfcDevice() {
|
||||
activate_event->Close();
|
||||
deactivate_event->Close();
|
||||
if (!is_controller_set) {
|
||||
return;
|
||||
}
|
||||
npad_device->DeleteCallback(callback_key);
|
||||
is_controller_set = false;
|
||||
};
|
||||
|
||||
void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (!is_initalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Core::HID::ControllerTriggerType::Connected) {
|
||||
Initialize();
|
||||
availability_change_event->Signal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Core::HID::ControllerTriggerType::Disconnected) {
|
||||
device_state = NFP::DeviceState::Unavailable;
|
||||
availability_change_event->Signal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != Core::HID::ControllerTriggerType::Nfc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!npad_device->IsConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto nfc_status = npad_device->GetNfc();
|
||||
switch (nfc_status.state) {
|
||||
case Common::Input::NfcState::NewAmiibo:
|
||||
LoadNfcTag(nfc_status.data);
|
||||
break;
|
||||
case Common::Input::NfcState::AmiiboRemoved:
|
||||
if (device_state != NFP::DeviceState::SearchingForTag) {
|
||||
CloseNfcTag();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
|
||||
if (device_state != NFP::DeviceState::SearchingForTag) {
|
||||
LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
|
||||
LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
tag_data.resize(data.size());
|
||||
memcpy(tag_data.data(), data.data(), data.size());
|
||||
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
|
||||
|
||||
device_state = NFP::DeviceState::TagFound;
|
||||
deactivate_event->GetReadableEvent().Clear();
|
||||
activate_event->Signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NfcDevice::CloseNfcTag() {
|
||||
LOG_INFO(Service_NFC, "Remove nfc tag");
|
||||
|
||||
device_state = NFP::DeviceState::TagRemoved;
|
||||
encrypted_tag_data = {};
|
||||
activate_event->GetReadableEvent().Clear();
|
||||
deactivate_event->Signal();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
|
||||
return activate_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
|
||||
return deactivate_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
void NfcDevice::Initialize() {
|
||||
device_state =
|
||||
npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
|
||||
encrypted_tag_data = {};
|
||||
is_initalized = true;
|
||||
}
|
||||
|
||||
void NfcDevice::Finalize() {
|
||||
if (device_state == NFP::DeviceState::SearchingForTag ||
|
||||
device_state == NFP::DeviceState::TagRemoved) {
|
||||
StopDetection();
|
||||
}
|
||||
device_state = NFP::DeviceState::Unavailable;
|
||||
is_initalized = false;
|
||||
}
|
||||
|
||||
Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) {
|
||||
if (device_state != NFP::DeviceState::Initialized &&
|
||||
device_state != NFP::DeviceState::TagRemoved) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::NFC) !=
|
||||
Common::Input::DriverResult::Success) {
|
||||
LOG_ERROR(Service_NFC, "Nfc not supported");
|
||||
return NfcDisabled;
|
||||
}
|
||||
|
||||
device_state = NFP::DeviceState::SearchingForTag;
|
||||
allowed_protocols = allowed_protocol;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::StopDetection() {
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
|
||||
if (device_state == NFP::DeviceState::Initialized) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
if (device_state == NFP::DeviceState::TagFound ||
|
||||
device_state == NFP::DeviceState::TagMounted) {
|
||||
CloseNfcTag();
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (device_state == NFP::DeviceState::SearchingForTag ||
|
||||
device_state == NFP::DeviceState::TagRemoved) {
|
||||
device_state = NFP::DeviceState::Initialized;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
Result NfcDevice::Flush() {
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (!npad_device->WriteNfc(tag_data)) {
|
||||
LOG_ERROR(Service_NFP, "Error writing to file");
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (is_mifare) {
|
||||
tag_info = {
|
||||
.uuid = encrypted_tag_data.uuid.uid,
|
||||
.uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
|
||||
.protocol = NFP::TagProtocol::TypeA,
|
||||
.tag_type = NFP::TagType::Type4,
|
||||
};
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
// Protocol and tag type may change here
|
||||
tag_info = {
|
||||
.uuid = encrypted_tag_data.uuid.uid,
|
||||
.uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
|
||||
.protocol = NFP::TagProtocol::TypeA,
|
||||
.tag_type = NFP::TagType::Type2,
|
||||
};
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
|
||||
NFP::MifareReadBlockData& read_block_data) {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
|
||||
read_block_data.sector_number = parameter.sector_number;
|
||||
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to read encrypted data
|
||||
memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
|
||||
|
||||
if (device_state != NFP::DeviceState::TagFound &&
|
||||
device_state != NFP::DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == NFP::DeviceState::TagRemoved) {
|
||||
return TagRemoved;
|
||||
}
|
||||
return WrongDeviceState;
|
||||
}
|
||||
|
||||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
|
||||
return MifareReadError;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to encrypt the data
|
||||
memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
u64 NfcDevice::GetHandle() const {
|
||||
// Generate a handle based of the npad id
|
||||
return static_cast<u64>(npad_id);
|
||||
}
|
||||
|
||||
NFP::DeviceState NfcDevice::GetCurrentState() const {
|
||||
return device_state;
|
||||
}
|
||||
|
||||
Core::HID::NpadIdType NfcDevice::GetNpadId() const {
|
||||
return npad_id;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -1,78 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
enum class ControllerTriggerType;
|
||||
enum class NpadIdType : u32;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice {
|
||||
public:
|
||||
NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_,
|
||||
Kernel::KEvent* availability_change_event_);
|
||||
~NfcDevice();
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
Result StartDetection(NFP::TagProtocol allowed_protocol);
|
||||
Result StopDetection();
|
||||
Result Flush();
|
||||
|
||||
Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
|
||||
|
||||
Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
|
||||
NFP::MifareReadBlockData& read_block_data);
|
||||
|
||||
Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
|
||||
|
||||
u64 GetHandle() const;
|
||||
NFP::DeviceState GetCurrentState() const;
|
||||
Core::HID::NpadIdType GetNpadId() const;
|
||||
|
||||
Kernel::KReadableEvent& GetActivateEvent() const;
|
||||
Kernel::KReadableEvent& GetDeactivateEvent() const;
|
||||
|
||||
private:
|
||||
void NpadUpdate(Core::HID::ControllerTriggerType type);
|
||||
bool LoadNfcTag(std::span<const u8> data);
|
||||
void CloseNfcTag();
|
||||
|
||||
bool is_controller_set{};
|
||||
int callback_key;
|
||||
const Core::HID::NpadIdType npad_id;
|
||||
Core::System& system;
|
||||
Core::HID::EmulatedController* npad_device = nullptr;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
Kernel::KEvent* activate_event = nullptr;
|
||||
Kernel::KEvent* deactivate_event = nullptr;
|
||||
Kernel::KEvent* availability_change_event = nullptr;
|
||||
|
||||
bool is_initalized{};
|
||||
NFP::TagProtocol allowed_protocols{};
|
||||
NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
|
||||
|
||||
NFP::EncryptedNTAG215File encrypted_tag_data{};
|
||||
std::vector<u8> tag_data{};
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -0,0 +1,382 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/nfc/common/device_manager.h"
|
||||
#include "core/hle/service/nfc/mifare_result.h"
|
||||
#include "core/hle/service/nfc/mifare_types.h"
|
||||
#include "core/hle/service/nfc/nfc_interface.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
|
||||
: ServiceFramework{system_, name}, service_context{system_, service_name},
|
||||
backend_type{service_backend} {}
|
||||
|
||||
NfcInterface ::~NfcInterface() = default;
|
||||
|
||||
void NfcInterface::Initialize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
auto manager = GetManager();
|
||||
auto result = manager->Initialize();
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
state = State::Initialized;
|
||||
} else {
|
||||
manager->Finalize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::Finalize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
if (state != State::NonInitialized) {
|
||||
if (GetBackendType() != BackendType::None) {
|
||||
GetManager()->Finalize();
|
||||
}
|
||||
device_manager = nullptr;
|
||||
state = State::NonInitialized;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void NfcInterface::GetState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(state);
|
||||
}
|
||||
|
||||
void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
|
||||
const bool is_enabled = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(is_enabled);
|
||||
}
|
||||
|
||||
void NfcInterface::ListDevices(HLERequestContext& ctx) {
|
||||
std::vector<u64> nfp_devices;
|
||||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(nfp_devices);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<s32>(nfp_devices.size()));
|
||||
}
|
||||
|
||||
void NfcInterface::GetDeviceState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
const auto device_state = GetManager()->GetDeviceState(device_handle);
|
||||
|
||||
if (device_state > DeviceState::Finalized) {
|
||||
ASSERT_MSG(false, "Invalid device state");
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device_state);
|
||||
}
|
||||
|
||||
void NfcInterface::GetNpadId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
Core::HID::NpadIdType npad_id{};
|
||||
auto result = GetManager()->GetNpadId(device_handle, npad_id);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(npad_id);
|
||||
}
|
||||
|
||||
void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
|
||||
}
|
||||
|
||||
void NfcInterface::StartDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
|
||||
|
||||
auto result = GetManager()->StartDetection(device_handle, tag_protocol);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::StopDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
auto result = GetManager()->StopDetection(device_handle);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
TagInfo tag_info{};
|
||||
auto result =
|
||||
GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
ctx.WriteBuffer(tag_info);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
|
||||
}
|
||||
|
||||
void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
|
||||
}
|
||||
|
||||
void NfcInterface::ReadMifare(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<MifareReadBlockParameter>()};
|
||||
std::vector<MifareReadBlockParameter> read_commands(number_of_commands);
|
||||
|
||||
memcpy(read_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(MifareReadBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
std::vector<MifareReadBlockData> out_data(number_of_commands);
|
||||
auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
ctx.WriteBuffer(out_data);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::WriteMifare(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto buffer{ctx.ReadBuffer()};
|
||||
const auto number_of_commands{ctx.GetReadBufferNumElements<MifareWriteBlockParameter>()};
|
||||
std::vector<MifareWriteBlockParameter> write_commands(number_of_commands);
|
||||
|
||||
memcpy(write_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(MifareWriteBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
|
||||
auto result = GetManager()->WriteMifare(device_handle, write_commands);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
|
||||
const auto command_data{ctx.ReadBuffer()};
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
|
||||
device_handle, timeout.ToSeconds(), command_data.size());
|
||||
|
||||
std::vector<u8> out_data(1);
|
||||
auto result =
|
||||
GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(out_data);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(out_data.size()));
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
|
||||
if (device_manager == nullptr) {
|
||||
device_manager = std::make_shared<DeviceManager>(system, service_context);
|
||||
}
|
||||
return device_manager;
|
||||
}
|
||||
|
||||
BackendType NfcInterface::GetBackendType() const {
|
||||
return backend_type;
|
||||
}
|
||||
|
||||
Result NfcInterface::TranslateResultToServiceError(Result result) const {
|
||||
const auto backend = GetBackendType();
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result.module != ErrorModule::NFC) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (backend) {
|
||||
case BackendType::Mifare:
|
||||
return TranslateResultToNfp(result);
|
||||
case BackendType::Nfp: {
|
||||
return TranslateResultToNfp(result);
|
||||
}
|
||||
default:
|
||||
if (result != ResultUnknown216) {
|
||||
return result;
|
||||
}
|
||||
return ResultUnknown74;
|
||||
}
|
||||
}
|
||||
|
||||
Result NfcInterface::TranslateResultToNfp(Result result) const {
|
||||
if (result == ResultDeviceNotFound) {
|
||||
return NFP::ResultDeviceNotFound;
|
||||
}
|
||||
if (result == ResultInvalidArgument) {
|
||||
return NFP::ResultInvalidArgument;
|
||||
}
|
||||
if (result == ResultWrongApplicationAreaSize) {
|
||||
return NFP::ResultWrongApplicationAreaSize;
|
||||
}
|
||||
if (result == ResultWrongDeviceState) {
|
||||
return NFP::ResultWrongDeviceState;
|
||||
}
|
||||
if (result == ResultUnknown74) {
|
||||
return NFP::ResultUnknown74;
|
||||
}
|
||||
if (result == ResultNfcDisabled) {
|
||||
return NFP::ResultNfcDisabled;
|
||||
}
|
||||
if (result == ResultNfcNotInitialized) {
|
||||
return NFP::ResultNfcDisabled;
|
||||
}
|
||||
if (result == ResultWriteAmiiboFailed) {
|
||||
return NFP::ResultWriteAmiiboFailed;
|
||||
}
|
||||
if (result == ResultTagRemoved) {
|
||||
return NFP::ResultTagRemoved;
|
||||
}
|
||||
if (result == ResultRegistrationIsNotInitialized) {
|
||||
return NFP::ResultRegistrationIsNotInitialized;
|
||||
}
|
||||
if (result == ResultApplicationAreaIsNotInitialized) {
|
||||
return NFP::ResultApplicationAreaIsNotInitialized;
|
||||
}
|
||||
if (result == ResultCorruptedData) {
|
||||
return NFP::ResultCorruptedData;
|
||||
}
|
||||
if (result == ResultWrongApplicationAreaId) {
|
||||
return NFP::ResultWrongApplicationAreaId;
|
||||
}
|
||||
if (result == ResultApplicationAreaExist) {
|
||||
return NFP::ResultApplicationAreaExist;
|
||||
}
|
||||
if (result == ResultNotAnAmiibo) {
|
||||
return NFP::ResultNotAnAmiibo;
|
||||
}
|
||||
LOG_WARNING(Service_NFC, "Result conversion not handled");
|
||||
return result;
|
||||
}
|
||||
|
||||
Result NfcInterface::TranslateResultToMifare(Result result) const {
|
||||
if (result == ResultDeviceNotFound) {
|
||||
return Mifare::ResultDeviceNotFound;
|
||||
}
|
||||
if (result == ResultInvalidArgument) {
|
||||
return Mifare::ResultInvalidArgument;
|
||||
}
|
||||
if (result == ResultWrongDeviceState) {
|
||||
return Mifare::ResultWrongDeviceState;
|
||||
}
|
||||
if (result == ResultNfcDisabled) {
|
||||
return Mifare::ResultNfcDisabled;
|
||||
}
|
||||
if (result == ResultTagRemoved) {
|
||||
return Mifare::ResultTagRemoved;
|
||||
}
|
||||
LOG_WARNING(Service_NFC, "Result conversion not handled");
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -3,26 +3,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
class NfcDevice;
|
||||
class DeviceManager;
|
||||
|
||||
class IUser final : public ServiceFramework<IUser> {
|
||||
class NfcInterface : public ServiceFramework<NfcInterface> {
|
||||
public:
|
||||
explicit IUser(Core::System& system_);
|
||||
~IUser();
|
||||
|
||||
private:
|
||||
enum class State : u32 {
|
||||
NonInitialized,
|
||||
Initialized,
|
||||
};
|
||||
explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
|
||||
~NfcInterface();
|
||||
|
||||
void Initialize(HLERequestContext& ctx);
|
||||
void Finalize(HLERequestContext& ctx);
|
||||
@@ -37,16 +28,22 @@ private:
|
||||
void GetTagInfo(HLERequestContext& ctx);
|
||||
void AttachActivateEvent(HLERequestContext& ctx);
|
||||
void AttachDeactivateEvent(HLERequestContext& ctx);
|
||||
void ReadMifare(HLERequestContext& ctx);
|
||||
void WriteMifare(HLERequestContext& ctx);
|
||||
void SendCommandByPassThrough(HLERequestContext& ctx);
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
|
||||
protected:
|
||||
std::shared_ptr<DeviceManager> GetManager();
|
||||
BackendType GetBackendType() const;
|
||||
Result TranslateResultToServiceError(Result result) const;
|
||||
Result TranslateResultToNfp(Result result) const;
|
||||
Result TranslateResultToMifare(Result result) const;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
|
||||
|
||||
BackendType backend_type;
|
||||
State state{State::NonInitialized};
|
||||
Kernel::KEvent* availability_change_event;
|
||||
std::shared_ptr<DeviceManager> device_manager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -7,17 +7,22 @@
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
constexpr Result DeviceNotFound(ErrorModule::NFC, 64);
|
||||
constexpr Result InvalidArgument(ErrorModule::NFC, 65);
|
||||
constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
|
||||
constexpr Result NfcDisabled(ErrorModule::NFC, 80);
|
||||
constexpr Result TagRemoved(ErrorModule::NFC, 97);
|
||||
|
||||
constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64);
|
||||
constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65);
|
||||
constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73);
|
||||
constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80);
|
||||
constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97);
|
||||
constexpr Result MifareReadError(ErrorModule::NFCMifare, 288);
|
||||
constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
|
||||
constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
|
||||
constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
|
||||
constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
|
||||
constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
|
||||
constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
|
||||
constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
|
||||
constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
|
||||
constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
|
||||
constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
|
||||
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
|
||||
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
|
||||
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
|
||||
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
|
||||
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
|
||||
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
|
||||
constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
|
||||
|
||||
} // namespace Service::NFC
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
enum class BackendType : u32 {
|
||||
None,
|
||||
Nfc,
|
||||
Nfp,
|
||||
Mifare,
|
||||
};
|
||||
|
||||
// This is nn::nfc::DeviceState
|
||||
enum class DeviceState : u32 {
|
||||
Initialized,
|
||||
SearchingForTag,
|
||||
TagFound,
|
||||
TagRemoved,
|
||||
TagMounted,
|
||||
Unavailable,
|
||||
Finalized,
|
||||
};
|
||||
|
||||
// This is nn::nfc::State
|
||||
enum class State : u32 {
|
||||
NonInitialized,
|
||||
Initialized,
|
||||
};
|
||||
|
||||
// This is nn::nfc::TagType
|
||||
enum class TagType : u32 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
};
|
||||
|
||||
enum class PackedTagType : u8 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
};
|
||||
|
||||
// This is nn::nfc::NfcProtocol
|
||||
// Verify this enum. It might be completely wrong default protocol is 0x48
|
||||
enum class NfcProtocol : u32 {
|
||||
None,
|
||||
TypeA = 1U << 0, // ISO14443A
|
||||
TypeB = 1U << 1, // ISO14443B
|
||||
TypeF = 1U << 2, // Sony FeliCa
|
||||
Unknown1 = 1U << 3,
|
||||
Unknown2 = 1U << 5,
|
||||
All = 0xFFFFFFFFU,
|
||||
};
|
||||
|
||||
// this is nn::nfc::TestWaveType
|
||||
enum class TestWaveType : u32 {
|
||||
Unknown,
|
||||
};
|
||||
|
||||
using UniqueSerialNumber = std::array<u8, 7>;
|
||||
using UniqueSerialNumberExtension = std::array<u8, 3>;
|
||||
|
||||
// This is nn::nfc::DeviceHandle
|
||||
using DeviceHandle = u64;
|
||||
|
||||
// This is nn::nfc::TagInfo
|
||||
struct TagInfo {
|
||||
UniqueSerialNumber uuid;
|
||||
UniqueSerialNumberExtension uuid_extension;
|
||||
u8 uuid_length;
|
||||
INSERT_PADDING_BYTES(0x15);
|
||||
NfcProtocol protocol;
|
||||
TagType tag_type;
|
||||
INSERT_PADDING_BYTES(0x30);
|
||||
};
|
||||
static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -1,365 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/nfc/nfc_device.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/nfc/nfc_user.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
|
||||
IUser::IUser(Core::System& system_)
|
||||
: ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IUser::Initialize, "InitializeOld"},
|
||||
{1, &IUser::Finalize, "FinalizeOld"},
|
||||
{2, &IUser::GetState, "GetStateOld"},
|
||||
{3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
|
||||
{400, &IUser::Initialize, "Initialize"},
|
||||
{401, &IUser::Finalize, "Finalize"},
|
||||
{402, &IUser::GetState, "GetState"},
|
||||
{403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
|
||||
{404, &IUser::ListDevices, "ListDevices"},
|
||||
{405, &IUser::GetDeviceState, "GetDeviceState"},
|
||||
{406, &IUser::GetNpadId, "GetNpadId"},
|
||||
{407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||
{408, &IUser::StartDetection, "StartDetection"},
|
||||
{409, &IUser::StopDetection, "StopDetection"},
|
||||
{410, &IUser::GetTagInfo, "GetTagInfo"},
|
||||
{411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
|
||||
{412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
|
||||
{1000, nullptr, "ReadMifare"},
|
||||
{1001, nullptr, "WriteMifare"},
|
||||
{1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
|
||||
{1301, nullptr, "KeepPassThroughSession"},
|
||||
{1302, nullptr, "ReleasePassThroughSession"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
|
||||
|
||||
for (u32 device_index = 0; device_index < 10; device_index++) {
|
||||
devices[device_index] =
|
||||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
|
||||
service_context, availability_change_event);
|
||||
}
|
||||
}
|
||||
|
||||
IUser ::~IUser() {
|
||||
availability_change_event->Close();
|
||||
}
|
||||
|
||||
void IUser::Initialize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::Initialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Initialize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IUser::Finalize(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
state = State::NonInitialized;
|
||||
|
||||
for (auto& device : devices) {
|
||||
device->Finalize();
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IUser::GetState(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(state);
|
||||
}
|
||||
|
||||
void IUser::IsNfcEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(state != State::NonInitialized);
|
||||
}
|
||||
|
||||
void IUser::ListDevices(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWriteBuffer()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.GetWriteBufferSize() == 0) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u64> nfp_devices;
|
||||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
|
||||
|
||||
for (auto& device : devices) {
|
||||
if (nfp_devices.size() >= max_allowed_devices) {
|
||||
continue;
|
||||
}
|
||||
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
|
||||
nfp_devices.push_back(device->GetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
if (nfp_devices.empty()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(nfp_devices);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<s32>(nfp_devices.size()));
|
||||
}
|
||||
|
||||
void IUser::GetDeviceState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetCurrentState());
|
||||
}
|
||||
|
||||
void IUser::GetNpadId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(device.value()->GetNpadId());
|
||||
}
|
||||
|
||||
void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(availability_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IUser::StartDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StartDetection(nfp_protocol);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IUser::StopDetection(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = device.value()->StopDetection();
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IUser::GetTagInfo(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
NFP::TagInfo tag_info{};
|
||||
const auto result = device.value()->GetTagInfo(tag_info, false);
|
||||
ctx.WriteBuffer(tag_info);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IUser::AttachActivateEvent(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetActivateEvent());
|
||||
}
|
||||
|
||||
void IUser::AttachDeactivateEvent(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(device.value()->GetDeactivateEvent());
|
||||
}
|
||||
|
||||
void IUser::SendCommandByPassThrough(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
|
||||
const auto command_data{ctx.ReadBuffer()};
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
|
||||
device_handle, timeout.ToSeconds(), command_data.size());
|
||||
|
||||
if (state == State::NonInitialized) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(NfcDisabled);
|
||||
return;
|
||||
}
|
||||
|
||||
auto device = GetNfcDevice(device_handle);
|
||||
|
||||
if (!device.has_value()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(DeviceNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> out_data(1);
|
||||
// TODO: Request data from nfc device
|
||||
ctx.WriteBuffer(out_data);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(out_data.size()));
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
|
||||
for (auto& device : devices) {
|
||||
if (device->GetHandle() == handle) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Service::NFC
|
||||
@@ -13,7 +13,7 @@ class IUser final : public Interface {
|
||||
public:
|
||||
explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
static const FunctionInfoTyped<IUser> functions[] = {
|
||||
{0, &IUser::Initialize, "Initialize"},
|
||||
{1, &IUser::Finalize, "Finalize"},
|
||||
{2, &IUser::ListDevices, "ListDevices"},
|
||||
@@ -50,7 +50,7 @@ class ISystem final : public Interface {
|
||||
public:
|
||||
explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
static const FunctionInfoTyped<ISystem> functions[] = {
|
||||
{0, &ISystem::InitializeSystem, "InitializeSystem"},
|
||||
{1, &ISystem::FinalizeSystem, "FinalizeSystem"},
|
||||
{2, &ISystem::ListDevices, "ListDevices"},
|
||||
@@ -89,7 +89,7 @@ class IDebug final : public Interface {
|
||||
public:
|
||||
explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
static const FunctionInfoTyped<IDebug> functions[] = {
|
||||
{0, &IDebug::InitializeDebug, "InitializeDebug"},
|
||||
{1, &IDebug::FinalizeDebug, "FinalizeDebug"},
|
||||
{2, &IDebug::ListDevices, "ListDevices"},
|
||||
@@ -126,9 +126,9 @@ public:
|
||||
{201, &IDebug::SetAll, "SetAll"},
|
||||
{202, &IDebug::FlushDebug, "FlushDebug"},
|
||||
{203, &IDebug::BreakTag, "BreakTag"},
|
||||
{204, nullptr, "ReadBackupData"},
|
||||
{205, nullptr, "WriteBackupData"},
|
||||
{206, nullptr, "WriteNtf"},
|
||||
{204, &IDebug::ReadBackupData, "ReadBackupData"},
|
||||
{205, &IDebug::WriteBackupData, "WriteBackupData"},
|
||||
{206, &IDebug::WriteNtf, "WriteNtf"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -152,16 +152,10 @@ private:
|
||||
void CreateUserInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
if (user_interface == nullptr) {
|
||||
user_interface = std::make_shared<IUser>(system);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IUser>(user_interface);
|
||||
rb.PushIpcInterface<IUser>(system);
|
||||
}
|
||||
|
||||
std::shared_ptr<IUser> user_interface;
|
||||
};
|
||||
|
||||
class ISystemManager final : public ServiceFramework<ISystemManager> {
|
||||
@@ -180,16 +174,10 @@ private:
|
||||
void CreateSystemInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
if (system_interface == nullptr) {
|
||||
system_interface = std::make_shared<ISystem>(system);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISystem>(system_interface);
|
||||
rb.PushIpcInterface<ISystem>(system);
|
||||
}
|
||||
|
||||
std::shared_ptr<ISystem> system_interface;
|
||||
};
|
||||
|
||||
class IDebugManager final : public ServiceFramework<IDebugManager> {
|
||||
@@ -208,16 +196,10 @@ private:
|
||||
void CreateDebugInterface(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NFP, "called");
|
||||
|
||||
if (system_interface == nullptr) {
|
||||
system_interface = std::make_shared<IDebug>(system);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebug>(system_interface);
|
||||
rb.PushIpcInterface<IDebug>(system);
|
||||
}
|
||||
|
||||
std::shared_ptr<IDebug> system_interface;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
enum class ControllerTriggerType;
|
||||
enum class NpadIdType : u32;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::NFP {
|
||||
class NfpDevice {
|
||||
public:
|
||||
NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_,
|
||||
Kernel::KEvent* availability_change_event_);
|
||||
~NfpDevice();
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
Result StartDetection(TagProtocol allowed_protocol);
|
||||
Result StopDetection();
|
||||
Result Mount(MountTarget mount_target);
|
||||
Result Unmount();
|
||||
|
||||
Result Flush();
|
||||
Result FlushDebug();
|
||||
Result FlushWithBreak(BreakType break_type);
|
||||
|
||||
Result GetTagInfo(TagInfo& tag_info) const;
|
||||
Result GetCommonInfo(CommonInfo& common_info) const;
|
||||
Result GetModelInfo(ModelInfo& model_info) const;
|
||||
Result GetRegisterInfo(RegisterInfo& register_info) const;
|
||||
Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const;
|
||||
Result GetAdminInfo(AdminInfo& admin_info) const;
|
||||
|
||||
Result DeleteRegisterInfo();
|
||||
Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name);
|
||||
Result RestoreAmiibo();
|
||||
Result Format();
|
||||
|
||||
Result OpenApplicationArea(u32 access_id);
|
||||
Result GetApplicationAreaId(u32& application_area_id) const;
|
||||
Result GetApplicationArea(std::vector<u8>& data) const;
|
||||
Result SetApplicationArea(std::span<const u8> data);
|
||||
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
|
||||
Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
|
||||
Result DeleteApplicationArea();
|
||||
Result ExistApplicationArea(bool& has_application_area);
|
||||
|
||||
Result GetAll(NfpData& data) const;
|
||||
Result SetAll(const NfpData& data);
|
||||
Result BreakTag(BreakType break_type);
|
||||
Result ReadBackupData();
|
||||
Result WriteBackupData();
|
||||
Result WriteNtf();
|
||||
|
||||
u64 GetHandle() const;
|
||||
u32 GetApplicationAreaSize() const;
|
||||
DeviceState GetCurrentState() const;
|
||||
Core::HID::NpadIdType GetNpadId() const;
|
||||
|
||||
Kernel::KReadableEvent& GetActivateEvent() const;
|
||||
Kernel::KReadableEvent& GetDeactivateEvent() const;
|
||||
|
||||
private:
|
||||
void NpadUpdate(Core::HID::ControllerTriggerType type);
|
||||
bool LoadAmiibo(std::span<const u8> data);
|
||||
void CloseAmiibo();
|
||||
|
||||
AmiiboName GetAmiiboName(const AmiiboSettings& settings) const;
|
||||
void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name);
|
||||
AmiiboDate GetAmiiboDate(s64 posix_time) const;
|
||||
u64 RemoveVersionByte(u64 application_id) const;
|
||||
void UpdateSettingsCrc();
|
||||
void UpdateRegisterInfoCrc();
|
||||
|
||||
bool is_controller_set{};
|
||||
int callback_key;
|
||||
const Core::HID::NpadIdType npad_id;
|
||||
Core::System& system;
|
||||
Core::HID::EmulatedController* npad_device = nullptr;
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
Kernel::KEvent* activate_event = nullptr;
|
||||
Kernel::KEvent* deactivate_event = nullptr;
|
||||
Kernel::KEvent* availability_change_event = nullptr;
|
||||
|
||||
bool is_initalized{};
|
||||
bool is_data_moddified{};
|
||||
bool is_app_area_open{};
|
||||
bool is_plain_amiibo{};
|
||||
TagProtocol allowed_protocols{};
|
||||
s64 current_posix_time{};
|
||||
MountTarget mount_target{MountTarget::None};
|
||||
DeviceState device_state{DeviceState::Unavailable};
|
||||
|
||||
NTAG215File tag_data{};
|
||||
EncryptedNTAG215File encrypted_tag_data{};
|
||||
};
|
||||
|
||||
} // namespace Service::NFP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +1,23 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nfc/nfc_interface.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NFP {
|
||||
class NfpDevice;
|
||||
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
class Interface : public NFC::NfcInterface {
|
||||
public:
|
||||
explicit Interface(Core::System& system_, const char* name);
|
||||
~Interface() override;
|
||||
|
||||
void Initialize(HLERequestContext& ctx);
|
||||
void InitializeSystem(HLERequestContext& ctx);
|
||||
void InitializeDebug(HLERequestContext& ctx);
|
||||
void Finalize(HLERequestContext& ctx);
|
||||
void FinalizeSystem(HLERequestContext& ctx);
|
||||
void FinalizeDebug(HLERequestContext& ctx);
|
||||
void ListDevices(HLERequestContext& ctx);
|
||||
void StartDetection(HLERequestContext& ctx);
|
||||
void StopDetection(HLERequestContext& ctx);
|
||||
void Mount(HLERequestContext& ctx);
|
||||
void Unmount(HLERequestContext& ctx);
|
||||
void OpenApplicationArea(HLERequestContext& ctx);
|
||||
@@ -35,17 +26,10 @@ public:
|
||||
void Flush(HLERequestContext& ctx);
|
||||
void Restore(HLERequestContext& ctx);
|
||||
void CreateApplicationArea(HLERequestContext& ctx);
|
||||
void GetTagInfo(HLERequestContext& ctx);
|
||||
void GetRegisterInfo(HLERequestContext& ctx);
|
||||
void GetCommonInfo(HLERequestContext& ctx);
|
||||
void GetModelInfo(HLERequestContext& ctx);
|
||||
void AttachActivateEvent(HLERequestContext& ctx);
|
||||
void AttachDeactivateEvent(HLERequestContext& ctx);
|
||||
void GetState(HLERequestContext& ctx);
|
||||
void GetDeviceState(HLERequestContext& ctx);
|
||||
void GetNpadId(HLERequestContext& ctx);
|
||||
void GetApplicationAreaSize(HLERequestContext& ctx);
|
||||
void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
|
||||
void RecreateApplicationArea(HLERequestContext& ctx);
|
||||
void Format(HLERequestContext& ctx);
|
||||
void GetAdminInfo(HLERequestContext& ctx);
|
||||
@@ -61,21 +45,6 @@ public:
|
||||
void ReadBackupData(HLERequestContext& ctx);
|
||||
void WriteBackupData(HLERequestContext& ctx);
|
||||
void WriteNtf(HLERequestContext& ctx);
|
||||
|
||||
private:
|
||||
enum class State : u32 {
|
||||
NonInitialized,
|
||||
Initialized,
|
||||
};
|
||||
|
||||
std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
std::array<std::shared_ptr<NfpDevice>, 10> devices{};
|
||||
|
||||
State state{State::NonInitialized};
|
||||
Kernel::KEvent* availability_change_event;
|
||||
};
|
||||
|
||||
} // namespace Service::NFP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -7,18 +7,19 @@
|
||||
|
||||
namespace Service::NFP {
|
||||
|
||||
constexpr Result DeviceNotFound(ErrorModule::NFP, 64);
|
||||
constexpr Result InvalidArgument(ErrorModule::NFP, 65);
|
||||
constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68);
|
||||
constexpr Result WrongDeviceState(ErrorModule::NFP, 73);
|
||||
constexpr Result NfcDisabled(ErrorModule::NFP, 80);
|
||||
constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88);
|
||||
constexpr Result TagRemoved(ErrorModule::NFP, 97);
|
||||
constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120);
|
||||
constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
|
||||
constexpr Result CorruptedData(ErrorModule::NFP, 144);
|
||||
constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152);
|
||||
constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168);
|
||||
constexpr Result NotAnAmiibo(ErrorModule::NFP, 178);
|
||||
constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64);
|
||||
constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65);
|
||||
constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
|
||||
constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73);
|
||||
constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
|
||||
constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80);
|
||||
constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
|
||||
constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
|
||||
constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
|
||||
constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
|
||||
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
|
||||
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
|
||||
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
|
||||
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
|
||||
|
||||
} // namespace Service::NFP
|
||||
|
||||
@@ -7,32 +7,19 @@
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/mii/types.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
|
||||
namespace Service::NFP {
|
||||
static constexpr std::size_t amiibo_name_length = 0xA;
|
||||
static constexpr std::size_t application_id_version_offset = 0x1c;
|
||||
static constexpr std::size_t counter_limit = 0xffff;
|
||||
|
||||
enum class ServiceType : u32 {
|
||||
User,
|
||||
Debug,
|
||||
System,
|
||||
};
|
||||
|
||||
enum class DeviceState : u32 {
|
||||
Initialized,
|
||||
SearchingForTag,
|
||||
TagFound,
|
||||
TagRemoved,
|
||||
TagMounted,
|
||||
Unavailable,
|
||||
Finalized,
|
||||
};
|
||||
|
||||
// This is nn::nfp::ModelType
|
||||
enum class ModelType : u32 {
|
||||
Amiibo,
|
||||
};
|
||||
|
||||
// This is nn::nfp::MountTarget
|
||||
enum class MountTarget : u32 {
|
||||
None,
|
||||
Rom,
|
||||
@@ -72,35 +59,6 @@ enum class AmiiboSeries : u8 {
|
||||
Diablo,
|
||||
};
|
||||
|
||||
enum class TagType : u32 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
};
|
||||
|
||||
enum class PackedTagType : u8 {
|
||||
None,
|
||||
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
|
||||
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
|
||||
Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
|
||||
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
|
||||
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
|
||||
};
|
||||
|
||||
// Verify this enum. It might be completely wrong default protocol is 0x48
|
||||
enum class TagProtocol : u32 {
|
||||
None,
|
||||
TypeA = 1U << 0, // ISO14443A
|
||||
TypeB = 1U << 1, // ISO14443B
|
||||
TypeF = 1U << 2, // Sony Felica
|
||||
Unknown1 = 1U << 3,
|
||||
Unknown2 = 1U << 5,
|
||||
All = 0xFFFFFFFFU,
|
||||
};
|
||||
|
||||
enum class AppAreaVersion : u8 {
|
||||
Nintendo3DS = 0,
|
||||
NintendoWiiU = 1,
|
||||
@@ -115,6 +73,11 @@ enum class BreakType : u32 {
|
||||
Unknown2,
|
||||
};
|
||||
|
||||
enum class WriteType : u32 {
|
||||
Unknown0,
|
||||
Unknown1,
|
||||
};
|
||||
|
||||
enum class CabinetMode : u8 {
|
||||
StartNicknameAndOwnerSettings,
|
||||
StartGameDataEraser,
|
||||
@@ -122,27 +85,16 @@ enum class CabinetMode : u8 {
|
||||
StartFormatter,
|
||||
};
|
||||
|
||||
enum class MifareCmd : u8 {
|
||||
AuthA = 0x60,
|
||||
AuthB = 0x61,
|
||||
Read = 0x30,
|
||||
Write = 0xA0,
|
||||
Transfer = 0xB0,
|
||||
Decrement = 0xC0,
|
||||
Increment = 0xC1,
|
||||
Store = 0xC2
|
||||
};
|
||||
|
||||
using UniqueSerialNumber = std::array<u8, 7>;
|
||||
using LockBytes = std::array<u8, 2>;
|
||||
using HashData = std::array<u8, 0x20>;
|
||||
using ApplicationArea = std::array<u8, 0xD8>;
|
||||
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
|
||||
using DataBlock = std::array<u8, 0x10>;
|
||||
using KeyData = std::array<u8, 0x6>;
|
||||
|
||||
// This is nn::nfp::TagInfo
|
||||
using TagInfo = NFC::TagInfo;
|
||||
|
||||
struct TagUuid {
|
||||
UniqueSerialNumber uid;
|
||||
NFC::UniqueSerialNumber uid;
|
||||
u8 nintendo_id;
|
||||
LockBytes lock_bytes;
|
||||
};
|
||||
@@ -243,7 +195,7 @@ struct AmiiboModelInfo {
|
||||
AmiiboType amiibo_type;
|
||||
u16_be model_number;
|
||||
AmiiboSeries series;
|
||||
PackedTagType tag_type;
|
||||
NFC::PackedTagType tag_type;
|
||||
INSERT_PADDING_BYTES(0x4); // Unknown
|
||||
};
|
||||
static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size");
|
||||
@@ -298,7 +250,7 @@ struct NTAG215File {
|
||||
u32_be register_info_crc;
|
||||
ApplicationArea application_area; // Encrypted Game data
|
||||
HashData hmac_tag; // Hash
|
||||
UniqueSerialNumber uid; // Unique serial number
|
||||
NFC::UniqueSerialNumber uid; // Unique serial number
|
||||
u8 nintendo_id; // Tag UUID
|
||||
AmiiboModelInfo model_info;
|
||||
HashData keygen_salt; // Salt
|
||||
@@ -326,17 +278,7 @@ static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File),
|
||||
static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>,
|
||||
"EncryptedNTAG215File must be trivially copyable.");
|
||||
|
||||
struct TagInfo {
|
||||
UniqueSerialNumber uuid;
|
||||
INSERT_PADDING_BYTES(0x3);
|
||||
u8 uuid_length;
|
||||
INSERT_PADDING_BYTES(0x15);
|
||||
TagProtocol protocol;
|
||||
TagType tag_type;
|
||||
INSERT_PADDING_BYTES(0x30);
|
||||
};
|
||||
static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
|
||||
|
||||
// This is nn::nfp::CommonInfo
|
||||
struct CommonInfo {
|
||||
WriteDate last_write_date;
|
||||
u16 write_counter;
|
||||
@@ -347,6 +289,7 @@ struct CommonInfo {
|
||||
};
|
||||
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
|
||||
|
||||
// This is nn::nfp::ModelInfo
|
||||
struct ModelInfo {
|
||||
u16 character_id;
|
||||
u8 character_variant;
|
||||
@@ -357,6 +300,7 @@ struct ModelInfo {
|
||||
};
|
||||
static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
|
||||
|
||||
// This is nn::nfp::RegisterInfo
|
||||
struct RegisterInfo {
|
||||
Service::Mii::CharInfo mii_char_info;
|
||||
WriteDate creation_date;
|
||||
@@ -366,6 +310,7 @@ struct RegisterInfo {
|
||||
};
|
||||
static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
|
||||
|
||||
// This is nn::nfp::RegisterInfoPrivate
|
||||
struct RegisterInfoPrivate {
|
||||
Service::Mii::MiiStoreData mii_store_data;
|
||||
WriteDate creation_date;
|
||||
@@ -375,12 +320,13 @@ struct RegisterInfoPrivate {
|
||||
};
|
||||
static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
|
||||
|
||||
// This is nn::nfp::AdminInfo
|
||||
struct AdminInfo {
|
||||
u64 application_id;
|
||||
u32 application_area_id;
|
||||
u16 crc_change_counter;
|
||||
u8 flags;
|
||||
PackedTagType tag_type;
|
||||
NFC::PackedTagType tag_type;
|
||||
AppAreaVersion app_area_version;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
INSERT_PADDING_BYTES(0x28);
|
||||
@@ -411,7 +357,7 @@ struct NfpData {
|
||||
u32 access_id;
|
||||
u16 settings_crc_counter;
|
||||
u8 font_region;
|
||||
PackedTagType tag_type;
|
||||
NFC::PackedTagType tag_type;
|
||||
AppAreaVersion console_type;
|
||||
u8 application_id_byte;
|
||||
INSERT_PADDING_BYTES(0x2E);
|
||||
@@ -420,37 +366,4 @@ struct NfpData {
|
||||
static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
|
||||
#pragma pack()
|
||||
|
||||
struct SectorKey {
|
||||
MifareCmd command;
|
||||
u8 unknown; // Usually 1
|
||||
INSERT_PADDING_BYTES(0x6);
|
||||
KeyData sector_key;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
};
|
||||
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
|
||||
|
||||
struct MifareReadBlockParameter {
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
|
||||
"MifareReadBlockParameter is an invalid size");
|
||||
|
||||
struct MifareReadBlockData {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
|
||||
|
||||
struct MifareWriteBlockParameter {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
};
|
||||
static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
|
||||
"MifareWriteBlockParameter is an invalid size");
|
||||
|
||||
} // namespace Service::NFP
|
||||
|
||||
@@ -218,7 +218,7 @@ public:
|
||||
|
||||
private:
|
||||
void Submit(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
if (state == RequestState::NotSubmitted) {
|
||||
UpdateState(RequestState::OnHold);
|
||||
@@ -229,7 +229,7 @@ private:
|
||||
}
|
||||
|
||||
void GetRequestState(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -237,7 +237,7 @@ private:
|
||||
}
|
||||
|
||||
void GetResult(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_NIFM, "(STUBBED) called");
|
||||
|
||||
const auto result = [this] {
|
||||
const auto has_connection = Network::GetHostIPv4Address().has_value();
|
||||
|
||||
@@ -793,6 +793,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
||||
std::scoped_lock lock{core->mutex};
|
||||
|
||||
slots[slot] = {};
|
||||
slots[slot].fence = Fence::NoFence();
|
||||
slots[slot].graphic_buffer = buffer;
|
||||
slots[slot].frame_number = 0;
|
||||
|
||||
@@ -854,7 +855,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
|
||||
|
||||
parcel_out.Write(slot);
|
||||
parcel_out.WriteObject(&fence);
|
||||
parcel_out.WriteFlattenedObject(&fence);
|
||||
break;
|
||||
}
|
||||
case TransactionId::RequestBuffer: {
|
||||
@@ -864,7 +865,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
|
||||
status = RequestBuffer(slot, &buf);
|
||||
|
||||
parcel_out.WriteObject(buf);
|
||||
parcel_out.WriteFlattenedObject(buf);
|
||||
break;
|
||||
}
|
||||
case TransactionId::QueueBuffer: {
|
||||
|
||||
@@ -117,61 +117,67 @@ private:
|
||||
|
||||
class OutputParcel final {
|
||||
public:
|
||||
static constexpr std::size_t DefaultBufferSize = 0x40;
|
||||
|
||||
OutputParcel() : buffer(DefaultBufferSize) {}
|
||||
|
||||
template <typename T>
|
||||
explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) {
|
||||
Write(out_data);
|
||||
}
|
||||
OutputParcel() = default;
|
||||
|
||||
template <typename T>
|
||||
void Write(const T& val) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
|
||||
|
||||
if (buffer.size() < write_index + sizeof(T)) {
|
||||
buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
|
||||
}
|
||||
|
||||
std::memcpy(buffer.data() + write_index, &val, sizeof(T));
|
||||
write_index += sizeof(T);
|
||||
write_index = Common::AlignUp(write_index, 4);
|
||||
this->WriteImpl(val, m_data_buffer);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void WriteObject(const T* ptr) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
|
||||
|
||||
void WriteFlattenedObject(const T* ptr) {
|
||||
if (!ptr) {
|
||||
Write<u32>(0);
|
||||
this->Write<u32>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
Write<u32>(1);
|
||||
Write<s64>(sizeof(T));
|
||||
Write(*ptr);
|
||||
this->Write<u32>(1);
|
||||
this->Write<s64>(sizeof(T));
|
||||
this->Write(*ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void WriteObject(const std::shared_ptr<T> ptr) {
|
||||
WriteObject(ptr.get());
|
||||
void WriteFlattenedObject(const std::shared_ptr<T> ptr) {
|
||||
this->WriteFlattenedObject(ptr.get());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void WriteInterface(const T& val) {
|
||||
this->WriteImpl(val, m_data_buffer);
|
||||
this->WriteImpl(0U, m_object_buffer);
|
||||
}
|
||||
|
||||
std::vector<u8> Serialize() const {
|
||||
ParcelHeader header{};
|
||||
header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader));
|
||||
header.data_offset = sizeof(ParcelHeader);
|
||||
header.objects_size = 4;
|
||||
header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size);
|
||||
std::memcpy(buffer.data(), &header, sizeof(ParcelHeader));
|
||||
std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
|
||||
m_object_buffer.size());
|
||||
|
||||
return buffer;
|
||||
ParcelHeader header{};
|
||||
header.data_size = static_cast<u32>(m_data_buffer.size());
|
||||
header.data_offset = sizeof(ParcelHeader);
|
||||
header.objects_size = static_cast<u32>(m_object_buffer.size());
|
||||
header.objects_offset = header.data_offset + header.data_size;
|
||||
|
||||
std::memcpy(output_buffer.data(), &header, sizeof(header));
|
||||
std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
|
||||
std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
|
||||
|
||||
return output_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::vector<u8> buffer;
|
||||
std::size_t write_index = sizeof(ParcelHeader);
|
||||
template <typename T>
|
||||
requires(std::is_trivially_copyable_v<T>)
|
||||
void WriteImpl(const T& val, std::vector<u8>& buffer) {
|
||||
const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
|
||||
const size_t old_size = buffer.size();
|
||||
buffer.resize(old_size + aligned_size);
|
||||
|
||||
std::memcpy(buffer.data() + old_size, &val, sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u8> m_data_buffer;
|
||||
std::vector<u8> m_object_buffer;
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user