y2r_u.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include "common/common_funcs.h"
  6. #include "common/common_types.h"
  7. #include "common/logging/log.h"
  8. #include "core/hle/kernel/event.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/service/y2r_u.h"
  11. #include "core/hw/y2r.h"
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////
  13. // Namespace Y2R_U
  14. namespace Y2R_U {
  15. struct ConversionParameters {
  16. InputFormat input_format;
  17. OutputFormat output_format;
  18. Rotation rotation;
  19. BlockAlignment block_alignment;
  20. u16 input_line_width;
  21. u16 input_lines;
  22. StandardCoefficient standard_coefficient;
  23. u8 padding;
  24. u16 alpha;
  25. };
  26. static_assert(sizeof(ConversionParameters) == 12, "ConversionParameters struct has incorrect size");
  27. static Kernel::SharedPtr<Kernel::Event> completion_event;
  28. static ConversionConfiguration conversion;
  29. static DitheringWeightParams dithering_weight_params;
  30. static u32 temporal_dithering_enabled = 0;
  31. static u32 transfer_end_interrupt_enabled = 0;
  32. static u32 spacial_dithering_enabled = 0;
  33. static const CoefficientSet standard_coefficients[4] = {
  34. {{0x100, 0x166, 0xB6, 0x58, 0x1C5, -0x166F, 0x10EE, -0x1C5B}}, // ITU_Rec601
  35. {{0x100, 0x193, 0x77, 0x2F, 0x1DB, -0x1933, 0xA7C, -0x1D51}}, // ITU_Rec709
  36. {{0x12A, 0x198, 0xD0, 0x64, 0x204, -0x1BDE, 0x10F2, -0x229B}}, // ITU_Rec601_Scaling
  37. {{0x12A, 0x1CA, 0x88, 0x36, 0x21C, -0x1F04, 0x99C, -0x2421}}, // ITU_Rec709_Scaling
  38. };
  39. ResultCode ConversionConfiguration::SetInputLineWidth(u16 width) {
  40. if (width == 0 || width > 1024 || width % 8 != 0) {
  41. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM,
  42. ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD
  43. }
  44. // Note: The hardware uses the register value 0 to represent a width of 1024, so for a width of
  45. // 1024 the `camera` module would set the value 0 here, but we don't need to emulate this
  46. // internal detail.
  47. this->input_line_width = width;
  48. return RESULT_SUCCESS;
  49. }
  50. ResultCode ConversionConfiguration::SetInputLines(u16 lines) {
  51. if (lines == 0 || lines > 1024) {
  52. return ResultCode(ErrorDescription::OutOfRange, ErrorModule::CAM,
  53. ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053FD
  54. }
  55. // Note: In what appears to be a bug, the `camera` module does not set the hardware register at
  56. // all if `lines` is 1024, so the conversion uses the last value that was set. The intention
  57. // was probably to set it to 0 like in SetInputLineWidth.
  58. if (lines != 1024) {
  59. this->input_lines = lines;
  60. }
  61. return RESULT_SUCCESS;
  62. }
  63. ResultCode ConversionConfiguration::SetStandardCoefficient(
  64. StandardCoefficient standard_coefficient) {
  65. size_t index = static_cast<size_t>(standard_coefficient);
  66. if (index >= ARRAY_SIZE(standard_coefficients)) {
  67. return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
  68. ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E053ED
  69. }
  70. std::memcpy(coefficients.data(), standard_coefficients[index].data(), sizeof(coefficients));
  71. return RESULT_SUCCESS;
  72. }
  73. static void SetInputFormat(Service::Interface* self) {
  74. u32* cmd_buff = Kernel::GetCommandBuffer();
  75. conversion.input_format = static_cast<InputFormat>(cmd_buff[1]);
  76. cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
  77. cmd_buff[1] = RESULT_SUCCESS.raw;
  78. LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
  79. }
  80. static void GetInputFormat(Service::Interface* self) {
  81. u32* cmd_buff = Kernel::GetCommandBuffer();
  82. cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0);
  83. cmd_buff[1] = RESULT_SUCCESS.raw;
  84. cmd_buff[2] = static_cast<u32>(conversion.input_format);
  85. LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
  86. }
  87. static void SetOutputFormat(Service::Interface* self) {
  88. u32* cmd_buff = Kernel::GetCommandBuffer();
  89. conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]);
  90. cmd_buff[0] = IPC::MakeHeader(0x3, 1, 0);
  91. cmd_buff[1] = RESULT_SUCCESS.raw;
  92. LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
  93. }
  94. static void GetOutputFormat(Service::Interface* self) {
  95. u32* cmd_buff = Kernel::GetCommandBuffer();
  96. cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0);
  97. cmd_buff[1] = RESULT_SUCCESS.raw;
  98. cmd_buff[2] = static_cast<u32>(conversion.output_format);
  99. LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
  100. }
  101. static void SetRotation(Service::Interface* self) {
  102. u32* cmd_buff = Kernel::GetCommandBuffer();
  103. conversion.rotation = static_cast<Rotation>(cmd_buff[1]);
  104. cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0);
  105. cmd_buff[1] = RESULT_SUCCESS.raw;
  106. LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
  107. }
  108. static void GetRotation(Service::Interface* self) {
  109. u32* cmd_buff = Kernel::GetCommandBuffer();
  110. cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0);
  111. cmd_buff[1] = RESULT_SUCCESS.raw;
  112. cmd_buff[2] = static_cast<u32>(conversion.rotation);
  113. LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
  114. }
  115. static void SetBlockAlignment(Service::Interface* self) {
  116. u32* cmd_buff = Kernel::GetCommandBuffer();
  117. conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]);
  118. cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0);
  119. cmd_buff[1] = RESULT_SUCCESS.raw;
  120. LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
  121. }
  122. static void GetBlockAlignment(Service::Interface* self) {
  123. u32* cmd_buff = Kernel::GetCommandBuffer();
  124. cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
  125. cmd_buff[1] = RESULT_SUCCESS.raw;
  126. cmd_buff[2] = static_cast<u32>(conversion.block_alignment);
  127. LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
  128. }
  129. /**
  130. * Y2R_U::SetSpacialDithering service function
  131. * Inputs:
  132. * 1 : u8, 0 = Disabled, 1 = Enabled
  133. * Outputs:
  134. * 1 : Result of function, 0 on success, otherwise error code
  135. */
  136. static void SetSpacialDithering(Service::Interface* self) {
  137. u32* cmd_buff = Kernel::GetCommandBuffer();
  138. spacial_dithering_enabled = cmd_buff[1] & 0xF;
  139. cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
  140. cmd_buff[1] = RESULT_SUCCESS.raw;
  141. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  142. }
  143. /**
  144. * Y2R_U::GetSpacialDithering service function
  145. * Outputs:
  146. * 1 : Result of function, 0 on success, otherwise error code
  147. * 2 : u8, 0 = Disabled, 1 = Enabled
  148. */
  149. static void GetSpacialDithering(Service::Interface* self) {
  150. u32* cmd_buff = Kernel::GetCommandBuffer();
  151. cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
  152. cmd_buff[1] = RESULT_SUCCESS.raw;
  153. cmd_buff[2] = spacial_dithering_enabled;
  154. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  155. }
  156. /**
  157. * Y2R_U::SetTemporalDithering service function
  158. * Inputs:
  159. * 1 : u8, 0 = Disabled, 1 = Enabled
  160. * Outputs:
  161. * 1 : Result of function, 0 on success, otherwise error code
  162. */
  163. static void SetTemporalDithering(Service::Interface* self) {
  164. u32* cmd_buff = Kernel::GetCommandBuffer();
  165. temporal_dithering_enabled = cmd_buff[1] & 0xF;
  166. cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0);
  167. cmd_buff[1] = RESULT_SUCCESS.raw;
  168. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  169. }
  170. /**
  171. * Y2R_U::GetTemporalDithering service function
  172. * Outputs:
  173. * 1 : Result of function, 0 on success, otherwise error code
  174. * 2 : u8, 0 = Disabled, 1 = Enabled
  175. */
  176. static void GetTemporalDithering(Service::Interface* self) {
  177. u32* cmd_buff = Kernel::GetCommandBuffer();
  178. cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
  179. cmd_buff[1] = RESULT_SUCCESS.raw;
  180. cmd_buff[2] = temporal_dithering_enabled;
  181. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  182. }
  183. /**
  184. * Y2R_U::SetTransferEndInterrupt service function
  185. * Inputs:
  186. * 1 : u8, 0 = Disabled, 1 = Enabled
  187. * Outputs:
  188. * 1 : Result of function, 0 on success, otherwise error code
  189. */
  190. static void SetTransferEndInterrupt(Service::Interface* self) {
  191. u32* cmd_buff = Kernel::GetCommandBuffer();
  192. transfer_end_interrupt_enabled = cmd_buff[1] & 0xf;
  193. cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0);
  194. cmd_buff[1] = RESULT_SUCCESS.raw;
  195. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  196. }
  197. /**
  198. * Y2R_U::GetTransferEndInterrupt service function
  199. * Outputs:
  200. * 1 : Result of function, 0 on success, otherwise error code
  201. * 2 : u8, 0 = Disabled, 1 = Enabled
  202. */
  203. static void GetTransferEndInterrupt(Service::Interface* self) {
  204. u32* cmd_buff = Kernel::GetCommandBuffer();
  205. cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0);
  206. cmd_buff[1] = RESULT_SUCCESS.raw;
  207. cmd_buff[2] = transfer_end_interrupt_enabled;
  208. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  209. }
  210. /**
  211. * Y2R_U::GetTransferEndEvent service function
  212. * Outputs:
  213. * 1 : Result of function, 0 on success, otherwise error code
  214. * 3 : The handle of the completion event
  215. */
  216. static void GetTransferEndEvent(Service::Interface* self) {
  217. u32* cmd_buff = Kernel::GetCommandBuffer();
  218. cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
  219. cmd_buff[1] = RESULT_SUCCESS.raw;
  220. cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom();
  221. LOG_DEBUG(Service_Y2R, "called");
  222. }
  223. static void SetSendingY(Service::Interface* self) {
  224. u32* cmd_buff = Kernel::GetCommandBuffer();
  225. conversion.src_Y.address = cmd_buff[1];
  226. conversion.src_Y.image_size = cmd_buff[2];
  227. conversion.src_Y.transfer_unit = cmd_buff[3];
  228. conversion.src_Y.gap = cmd_buff[4];
  229. cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
  230. cmd_buff[1] = RESULT_SUCCESS.raw;
  231. LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
  232. "src_process_handle=0x%08X",
  233. conversion.src_Y.image_size, conversion.src_Y.transfer_unit, conversion.src_Y.gap,
  234. cmd_buff[6]);
  235. }
  236. static void SetSendingU(Service::Interface* self) {
  237. u32* cmd_buff = Kernel::GetCommandBuffer();
  238. conversion.src_U.address = cmd_buff[1];
  239. conversion.src_U.image_size = cmd_buff[2];
  240. conversion.src_U.transfer_unit = cmd_buff[3];
  241. conversion.src_U.gap = cmd_buff[4];
  242. cmd_buff[0] = IPC::MakeHeader(0x11, 1, 0);
  243. cmd_buff[1] = RESULT_SUCCESS.raw;
  244. LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
  245. "src_process_handle=0x%08X",
  246. conversion.src_U.image_size, conversion.src_U.transfer_unit, conversion.src_U.gap,
  247. cmd_buff[6]);
  248. }
  249. static void SetSendingV(Service::Interface* self) {
  250. u32* cmd_buff = Kernel::GetCommandBuffer();
  251. conversion.src_V.address = cmd_buff[1];
  252. conversion.src_V.image_size = cmd_buff[2];
  253. conversion.src_V.transfer_unit = cmd_buff[3];
  254. conversion.src_V.gap = cmd_buff[4];
  255. cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
  256. cmd_buff[1] = RESULT_SUCCESS.raw;
  257. LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
  258. "src_process_handle=0x%08X",
  259. conversion.src_V.image_size, conversion.src_V.transfer_unit, conversion.src_V.gap,
  260. cmd_buff[6]);
  261. }
  262. static void SetSendingYUYV(Service::Interface* self) {
  263. u32* cmd_buff = Kernel::GetCommandBuffer();
  264. conversion.src_YUYV.address = cmd_buff[1];
  265. conversion.src_YUYV.image_size = cmd_buff[2];
  266. conversion.src_YUYV.transfer_unit = cmd_buff[3];
  267. conversion.src_YUYV.gap = cmd_buff[4];
  268. cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
  269. cmd_buff[1] = RESULT_SUCCESS.raw;
  270. LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
  271. "src_process_handle=0x%08X",
  272. conversion.src_YUYV.image_size, conversion.src_YUYV.transfer_unit,
  273. conversion.src_YUYV.gap, cmd_buff[6]);
  274. }
  275. /**
  276. * Y2R::IsFinishedSendingYuv service function
  277. * Output:
  278. * 1 : Result of the function, 0 on success, otherwise error code
  279. * 2 : u8, 0 = Not Finished, 1 = Finished
  280. */
  281. static void IsFinishedSendingYuv(Service::Interface* self) {
  282. u32* cmd_buff = Kernel::GetCommandBuffer();
  283. cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0);
  284. cmd_buff[1] = RESULT_SUCCESS.raw;
  285. cmd_buff[2] = 1;
  286. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  287. }
  288. /**
  289. * Y2R::IsFinishedSendingY service function
  290. * Output:
  291. * 1 : Result of the function, 0 on success, otherwise error code
  292. * 2 : u8, 0 = Not Finished, 1 = Finished
  293. */
  294. static void IsFinishedSendingY(Service::Interface* self) {
  295. u32* cmd_buff = Kernel::GetCommandBuffer();
  296. cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0);
  297. cmd_buff[1] = RESULT_SUCCESS.raw;
  298. cmd_buff[2] = 1;
  299. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  300. }
  301. /**
  302. * Y2R::IsFinishedSendingU service function
  303. * Output:
  304. * 1 : Result of the function, 0 on success, otherwise error code
  305. * 2 : u8, 0 = Not Finished, 1 = Finished
  306. */
  307. static void IsFinishedSendingU(Service::Interface* self) {
  308. u32* cmd_buff = Kernel::GetCommandBuffer();
  309. cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
  310. cmd_buff[1] = RESULT_SUCCESS.raw;
  311. cmd_buff[2] = 1;
  312. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  313. }
  314. /**
  315. * Y2R::IsFinishedSendingV service function
  316. * Output:
  317. * 1 : Result of the function, 0 on success, otherwise error code
  318. * 2 : u8, 0 = Not Finished, 1 = Finished
  319. */
  320. static void IsFinishedSendingV(Service::Interface* self) {
  321. u32* cmd_buff = Kernel::GetCommandBuffer();
  322. cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0);
  323. cmd_buff[1] = RESULT_SUCCESS.raw;
  324. cmd_buff[2] = 1;
  325. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  326. }
  327. static void SetReceiving(Service::Interface* self) {
  328. u32* cmd_buff = Kernel::GetCommandBuffer();
  329. conversion.dst.address = cmd_buff[1];
  330. conversion.dst.image_size = cmd_buff[2];
  331. conversion.dst.transfer_unit = cmd_buff[3];
  332. conversion.dst.gap = cmd_buff[4];
  333. cmd_buff[0] = IPC::MakeHeader(0x18, 1, 0);
  334. cmd_buff[1] = RESULT_SUCCESS.raw;
  335. LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
  336. "dst_process_handle=0x%08X",
  337. conversion.dst.image_size, conversion.dst.transfer_unit, conversion.dst.gap,
  338. cmd_buff[6]);
  339. }
  340. /**
  341. * Y2R::IsFinishedReceiving service function
  342. * Output:
  343. * 1 : Result of the function, 0 on success, otherwise error code
  344. * 2 : u8, 0 = Not Finished, 1 = Finished
  345. */
  346. static void IsFinishedReceiving(Service::Interface* self) {
  347. u32* cmd_buff = Kernel::GetCommandBuffer();
  348. cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0);
  349. cmd_buff[1] = RESULT_SUCCESS.raw;
  350. cmd_buff[2] = 1;
  351. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  352. }
  353. static void SetInputLineWidth(Service::Interface* self) {
  354. u32* cmd_buff = Kernel::GetCommandBuffer();
  355. cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0);
  356. cmd_buff[1] = conversion.SetInputLineWidth(cmd_buff[1]).raw;
  357. LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]);
  358. }
  359. static void GetInputLineWidth(Service::Interface* self) {
  360. u32* cmd_buff = Kernel::GetCommandBuffer();
  361. cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0);
  362. cmd_buff[1] = RESULT_SUCCESS.raw;
  363. cmd_buff[2] = conversion.input_line_width;
  364. LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width);
  365. }
  366. static void SetInputLines(Service::Interface* self) {
  367. u32* cmd_buff = Kernel::GetCommandBuffer();
  368. cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0);
  369. cmd_buff[1] = conversion.SetInputLines(cmd_buff[1]).raw;
  370. LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]);
  371. }
  372. static void GetInputLines(Service::Interface* self) {
  373. u32* cmd_buff = Kernel::GetCommandBuffer();
  374. cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0);
  375. cmd_buff[1] = RESULT_SUCCESS.raw;
  376. cmd_buff[2] = static_cast<u32>(conversion.input_lines);
  377. LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines);
  378. }
  379. static void SetCoefficient(Service::Interface* self) {
  380. u32* cmd_buff = Kernel::GetCommandBuffer();
  381. const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]);
  382. std::memcpy(conversion.coefficients.data(), coefficients, sizeof(CoefficientSet));
  383. cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0);
  384. cmd_buff[1] = RESULT_SUCCESS.raw;
  385. LOG_DEBUG(Service_Y2R, "called coefficients=[%hX, %hX, %hX, %hX, %hX, %hX, %hX, %hX]",
  386. coefficients[0], coefficients[1], coefficients[2], coefficients[3], coefficients[4],
  387. coefficients[5], coefficients[6], coefficients[7]);
  388. }
  389. static void GetCoefficient(Service::Interface* self) {
  390. u32* cmd_buff = Kernel::GetCommandBuffer();
  391. cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0);
  392. cmd_buff[1] = RESULT_SUCCESS.raw;
  393. std::memcpy(&cmd_buff[2], conversion.coefficients.data(), sizeof(CoefficientSet));
  394. LOG_DEBUG(Service_Y2R, "called");
  395. }
  396. static void SetStandardCoefficient(Service::Interface* self) {
  397. u32* cmd_buff = Kernel::GetCommandBuffer();
  398. u32 index = cmd_buff[1];
  399. cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
  400. cmd_buff[1] = conversion.SetStandardCoefficient((StandardCoefficient)index).raw;
  401. LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index);
  402. }
  403. static void GetStandardCoefficient(Service::Interface* self) {
  404. u32* cmd_buff = Kernel::GetCommandBuffer();
  405. u32 index = cmd_buff[1];
  406. if (index < ARRAY_SIZE(standard_coefficients)) {
  407. cmd_buff[0] = IPC::MakeHeader(0x21, 5, 0);
  408. cmd_buff[1] = RESULT_SUCCESS.raw;
  409. std::memcpy(&cmd_buff[2], &standard_coefficients[index], sizeof(CoefficientSet));
  410. LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u ", index);
  411. } else {
  412. cmd_buff[0] = IPC::MakeHeader(0x21, 1, 0);
  413. cmd_buff[1] = -1; // TODO(bunnei): Identify the correct error code for this
  414. LOG_ERROR(Service_Y2R, "called standard_coefficient=%u The argument is invalid!", index);
  415. }
  416. }
  417. static void SetAlpha(Service::Interface* self) {
  418. u32* cmd_buff = Kernel::GetCommandBuffer();
  419. conversion.alpha = cmd_buff[1];
  420. cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0);
  421. cmd_buff[1] = RESULT_SUCCESS.raw;
  422. LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
  423. }
  424. static void GetAlpha(Service::Interface* self) {
  425. u32* cmd_buff = Kernel::GetCommandBuffer();
  426. cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0);
  427. cmd_buff[1] = RESULT_SUCCESS.raw;
  428. cmd_buff[2] = conversion.alpha;
  429. LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
  430. }
  431. static void SetDitheringWeightParams(Service::Interface* self) {
  432. u32* cmd_buff = Kernel::GetCommandBuffer();
  433. std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams));
  434. cmd_buff[0] = IPC::MakeHeader(0x24, 1, 0);
  435. cmd_buff[1] = RESULT_SUCCESS.raw;
  436. LOG_DEBUG(Service_Y2R, "called");
  437. }
  438. static void GetDitheringWeightParams(Service::Interface* self) {
  439. u32* cmd_buff = Kernel::GetCommandBuffer();
  440. cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0);
  441. cmd_buff[1] = RESULT_SUCCESS.raw;
  442. std::memcpy(&cmd_buff[2], &dithering_weight_params, sizeof(DitheringWeightParams));
  443. LOG_DEBUG(Service_Y2R, "called");
  444. }
  445. static void StartConversion(Service::Interface* self) {
  446. u32* cmd_buff = Kernel::GetCommandBuffer();
  447. // dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
  448. u32 total_output_size =
  449. conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap);
  450. Memory::RasterizerFlushAndInvalidateRegion(
  451. Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size);
  452. HW::Y2R::PerformConversion(conversion);
  453. completion_event->Signal();
  454. cmd_buff[0] = IPC::MakeHeader(0x26, 1, 0);
  455. cmd_buff[1] = RESULT_SUCCESS.raw;
  456. LOG_DEBUG(Service_Y2R, "called");
  457. }
  458. static void StopConversion(Service::Interface* self) {
  459. u32* cmd_buff = Kernel::GetCommandBuffer();
  460. cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0);
  461. cmd_buff[1] = RESULT_SUCCESS.raw;
  462. LOG_DEBUG(Service_Y2R, "called");
  463. }
  464. /**
  465. * Y2R_U::IsBusyConversion service function
  466. * Outputs:
  467. * 1 : Result of function, 0 on success, otherwise error code
  468. * 2 : 1 if there's a conversion running, otherwise 0.
  469. */
  470. static void IsBusyConversion(Service::Interface* self) {
  471. u32* cmd_buff = Kernel::GetCommandBuffer();
  472. cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0);
  473. cmd_buff[1] = RESULT_SUCCESS.raw;
  474. cmd_buff[2] = 0; // StartConversion always finishes immediately
  475. LOG_DEBUG(Service_Y2R, "called");
  476. }
  477. /**
  478. * Y2R_U::SetPackageParameter service function
  479. */
  480. static void SetPackageParameter(Service::Interface* self) {
  481. u32* cmd_buff = Kernel::GetCommandBuffer();
  482. auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]);
  483. conversion.input_format = params->input_format;
  484. conversion.output_format = params->output_format;
  485. conversion.rotation = params->rotation;
  486. conversion.block_alignment = params->block_alignment;
  487. ResultCode result = conversion.SetInputLineWidth(params->input_line_width);
  488. if (result.IsError())
  489. goto cleanup;
  490. result = conversion.SetInputLines(params->input_lines);
  491. if (result.IsError())
  492. goto cleanup;
  493. result = conversion.SetStandardCoefficient(params->standard_coefficient);
  494. if (result.IsError())
  495. goto cleanup;
  496. conversion.padding = params->padding;
  497. conversion.alpha = params->alpha;
  498. cleanup:
  499. cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0);
  500. cmd_buff[1] = result.raw;
  501. LOG_DEBUG(
  502. Service_Y2R,
  503. "called input_format=%hhu output_format=%hhu rotation=%hhu block_alignment=%hhu "
  504. "input_line_width=%hu input_lines=%hu standard_coefficient=%hhu reserved=%hhu alpha=%hX",
  505. params->input_format, params->output_format, params->rotation, params->block_alignment,
  506. params->input_line_width, params->input_lines, params->standard_coefficient,
  507. params->padding, params->alpha);
  508. }
  509. static void PingProcess(Service::Interface* self) {
  510. u32* cmd_buff = Kernel::GetCommandBuffer();
  511. cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0);
  512. cmd_buff[1] = RESULT_SUCCESS.raw;
  513. cmd_buff[2] = 0;
  514. LOG_WARNING(Service_Y2R, "(STUBBED) called");
  515. }
  516. static void DriverInitialize(Service::Interface* self) {
  517. u32* cmd_buff = Kernel::GetCommandBuffer();
  518. conversion.input_format = InputFormat::YUV422_Indiv8;
  519. conversion.output_format = OutputFormat::RGBA8;
  520. conversion.rotation = Rotation::None;
  521. conversion.block_alignment = BlockAlignment::Linear;
  522. conversion.coefficients.fill(0);
  523. conversion.SetInputLineWidth(1024);
  524. conversion.SetInputLines(1024);
  525. conversion.alpha = 0;
  526. ConversionBuffer zero_buffer = {};
  527. conversion.src_Y = zero_buffer;
  528. conversion.src_U = zero_buffer;
  529. conversion.src_V = zero_buffer;
  530. conversion.dst = zero_buffer;
  531. completion_event->Clear();
  532. cmd_buff[0] = IPC::MakeHeader(0x2B, 1, 0);
  533. cmd_buff[1] = RESULT_SUCCESS.raw;
  534. LOG_DEBUG(Service_Y2R, "called");
  535. }
  536. static void DriverFinalize(Service::Interface* self) {
  537. u32* cmd_buff = Kernel::GetCommandBuffer();
  538. cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0);
  539. cmd_buff[1] = RESULT_SUCCESS.raw;
  540. LOG_DEBUG(Service_Y2R, "called");
  541. }
  542. static void GetPackageParameter(Service::Interface* self) {
  543. u32* cmd_buff = Kernel::GetCommandBuffer();
  544. cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0);
  545. cmd_buff[1] = RESULT_SUCCESS.raw;
  546. std::memcpy(&cmd_buff[2], &conversion, sizeof(ConversionParameters));
  547. LOG_DEBUG(Service_Y2R, "called");
  548. }
  549. const Interface::FunctionInfo FunctionTable[] = {
  550. {0x00010040, SetInputFormat, "SetInputFormat"},
  551. {0x00020000, GetInputFormat, "GetInputFormat"},
  552. {0x00030040, SetOutputFormat, "SetOutputFormat"},
  553. {0x00040000, GetOutputFormat, "GetOutputFormat"},
  554. {0x00050040, SetRotation, "SetRotation"},
  555. {0x00060000, GetRotation, "GetRotation"},
  556. {0x00070040, SetBlockAlignment, "SetBlockAlignment"},
  557. {0x00080000, GetBlockAlignment, "GetBlockAlignment"},
  558. {0x00090040, SetSpacialDithering, "SetSpacialDithering"},
  559. {0x000A0000, GetSpacialDithering, "GetSpacialDithering"},
  560. {0x000B0040, SetTemporalDithering, "SetTemporalDithering"},
  561. {0x000C0000, GetTemporalDithering, "GetTemporalDithering"},
  562. {0x000D0040, SetTransferEndInterrupt, "SetTransferEndInterrupt"},
  563. {0x000E0000, GetTransferEndInterrupt, "GetTransferEndInterrupt"},
  564. {0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"},
  565. {0x00100102, SetSendingY, "SetSendingY"},
  566. {0x00110102, SetSendingU, "SetSendingU"},
  567. {0x00120102, SetSendingV, "SetSendingV"},
  568. {0x00130102, SetSendingYUYV, "SetSendingYUYV"},
  569. {0x00140000, IsFinishedSendingYuv, "IsFinishedSendingYuv"},
  570. {0x00150000, IsFinishedSendingY, "IsFinishedSendingY"},
  571. {0x00160000, IsFinishedSendingU, "IsFinishedSendingU"},
  572. {0x00170000, IsFinishedSendingV, "IsFinishedSendingV"},
  573. {0x00180102, SetReceiving, "SetReceiving"},
  574. {0x00190000, IsFinishedReceiving, "IsFinishedReceiving"},
  575. {0x001A0040, SetInputLineWidth, "SetInputLineWidth"},
  576. {0x001B0000, GetInputLineWidth, "GetInputLineWidth"},
  577. {0x001C0040, SetInputLines, "SetInputLines"},
  578. {0x001D0000, GetInputLines, "GetInputLines"},
  579. {0x001E0100, SetCoefficient, "SetCoefficient"},
  580. {0x001F0000, GetCoefficient, "GetCoefficient"},
  581. {0x00200040, SetStandardCoefficient, "SetStandardCoefficient"},
  582. {0x00210040, GetStandardCoefficient, "GetStandardCoefficient"},
  583. {0x00220040, SetAlpha, "SetAlpha"},
  584. {0x00230000, GetAlpha, "GetAlpha"},
  585. {0x00240200, SetDitheringWeightParams, "SetDitheringWeightParams"},
  586. {0x00250000, GetDitheringWeightParams, "GetDitheringWeightParams"},
  587. {0x00260000, StartConversion, "StartConversion"},
  588. {0x00270000, StopConversion, "StopConversion"},
  589. {0x00280000, IsBusyConversion, "IsBusyConversion"},
  590. {0x002901C0, SetPackageParameter, "SetPackageParameter"},
  591. {0x002A0000, PingProcess, "PingProcess"},
  592. {0x002B0000, DriverInitialize, "DriverInitialize"},
  593. {0x002C0000, DriverFinalize, "DriverFinalize"},
  594. {0x002D0000, GetPackageParameter, "GetPackageParameter"},
  595. };
  596. ////////////////////////////////////////////////////////////////////////////////////////////////////
  597. // Interface class
  598. Interface::Interface() {
  599. completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed");
  600. std::memset(&conversion, 0, sizeof(conversion));
  601. Register(FunctionTable);
  602. }
  603. Interface::~Interface() {
  604. completion_event = nullptr;
  605. }
  606. } // namespace