hdcp.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * Copyright 2019 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: AMD
  23. *
  24. */
  25. #include "hdcp.h"
  26. static void push_error_status(struct mod_hdcp *hdcp,
  27. enum mod_hdcp_status status)
  28. {
  29. struct mod_hdcp_trace *trace = &hdcp->connection.trace;
  30. if (trace->error_count < MAX_NUM_OF_ERROR_TRACE) {
  31. trace->errors[trace->error_count].status = status;
  32. trace->errors[trace->error_count].state_id = hdcp->state.id;
  33. trace->error_count++;
  34. HDCP_ERROR_TRACE(hdcp, status);
  35. }
  36. if (is_hdcp1(hdcp)) {
  37. hdcp->connection.hdcp1_retry_count++;
  38. if (hdcp->connection.hdcp1_retry_count == MAX_NUM_OF_ATTEMPTS)
  39. hdcp->connection.link.adjust.hdcp1.disable = 1;
  40. } else if (is_hdcp2(hdcp)) {
  41. hdcp->connection.hdcp2_retry_count++;
  42. if (hdcp->connection.hdcp2_retry_count == MAX_NUM_OF_ATTEMPTS)
  43. hdcp->connection.link.adjust.hdcp2.disable = 1;
  44. }
  45. }
  46. static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp)
  47. {
  48. int i, is_auth_needed = 0;
  49. /* if all displays on the link don't need authentication,
  50. * hdcp is not desired
  51. */
  52. for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
  53. if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
  54. hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) {
  55. is_auth_needed = 1;
  56. break;
  57. }
  58. }
  59. return is_auth_needed &&
  60. !hdcp->connection.link.adjust.hdcp1.disable &&
  61. !hdcp->connection.is_hdcp1_revoked;
  62. }
  63. static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp)
  64. {
  65. int i, is_auth_needed = 0;
  66. /* if all displays on the link don't need authentication,
  67. * hdcp is not desired
  68. */
  69. for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
  70. if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
  71. hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) {
  72. is_auth_needed = 1;
  73. break;
  74. }
  75. }
  76. return is_auth_needed &&
  77. !hdcp->connection.link.adjust.hdcp2.disable &&
  78. !hdcp->connection.is_hdcp2_revoked;
  79. }
  80. static enum mod_hdcp_status execution(struct mod_hdcp *hdcp,
  81. struct mod_hdcp_event_context *event_ctx,
  82. union mod_hdcp_transition_input *input)
  83. {
  84. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  85. if (is_in_initialized_state(hdcp)) {
  86. if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
  87. event_ctx->unexpected_event = 1;
  88. goto out;
  89. }
  90. /* initialize transition input */
  91. memset(input, 0, sizeof(union mod_hdcp_transition_input));
  92. } else if (is_in_cp_not_desired_state(hdcp)) {
  93. if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
  94. event_ctx->unexpected_event = 1;
  95. goto out;
  96. }
  97. } else if (is_in_hdcp1_states(hdcp)) {
  98. status = mod_hdcp_hdcp1_execution(hdcp, event_ctx, &input->hdcp1);
  99. } else if (is_in_hdcp1_dp_states(hdcp)) {
  100. status = mod_hdcp_hdcp1_dp_execution(hdcp,
  101. event_ctx, &input->hdcp1);
  102. } else if (is_in_hdcp2_states(hdcp)) {
  103. status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2);
  104. } else if (is_in_hdcp2_dp_states(hdcp)) {
  105. status = mod_hdcp_hdcp2_dp_execution(hdcp,
  106. event_ctx, &input->hdcp2);
  107. } else {
  108. event_ctx->unexpected_event = 1;
  109. goto out;
  110. }
  111. out:
  112. return status;
  113. }
  114. static enum mod_hdcp_status transition(struct mod_hdcp *hdcp,
  115. struct mod_hdcp_event_context *event_ctx,
  116. union mod_hdcp_transition_input *input,
  117. struct mod_hdcp_output *output)
  118. {
  119. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  120. if (event_ctx->unexpected_event)
  121. goto out;
  122. if (is_in_initialized_state(hdcp)) {
  123. if (is_dp_hdcp(hdcp))
  124. if (is_cp_desired_hdcp2(hdcp)) {
  125. callback_in_ms(0, output);
  126. set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE);
  127. } else if (is_cp_desired_hdcp1(hdcp)) {
  128. callback_in_ms(0, output);
  129. set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE);
  130. } else {
  131. callback_in_ms(0, output);
  132. set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
  133. set_auth_complete(hdcp, output);
  134. }
  135. else if (is_hdmi_dvi_sl_hdcp(hdcp))
  136. if (is_cp_desired_hdcp2(hdcp)) {
  137. callback_in_ms(0, output);
  138. set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX);
  139. } else if (is_cp_desired_hdcp1(hdcp)) {
  140. callback_in_ms(0, output);
  141. set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX);
  142. } else {
  143. callback_in_ms(0, output);
  144. set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
  145. set_auth_complete(hdcp, output);
  146. }
  147. else {
  148. callback_in_ms(0, output);
  149. set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
  150. set_auth_complete(hdcp, output);
  151. }
  152. } else if (is_in_cp_not_desired_state(hdcp)) {
  153. increment_stay_counter(hdcp);
  154. } else if (is_in_hdcp1_states(hdcp)) {
  155. status = mod_hdcp_hdcp1_transition(hdcp,
  156. event_ctx, &input->hdcp1, output);
  157. } else if (is_in_hdcp1_dp_states(hdcp)) {
  158. status = mod_hdcp_hdcp1_dp_transition(hdcp,
  159. event_ctx, &input->hdcp1, output);
  160. } else if (is_in_hdcp2_states(hdcp)) {
  161. status = mod_hdcp_hdcp2_transition(hdcp,
  162. event_ctx, &input->hdcp2, output);
  163. } else if (is_in_hdcp2_dp_states(hdcp)) {
  164. status = mod_hdcp_hdcp2_dp_transition(hdcp,
  165. event_ctx, &input->hdcp2, output);
  166. } else {
  167. status = MOD_HDCP_STATUS_INVALID_STATE;
  168. }
  169. out:
  170. return status;
  171. }
  172. static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp,
  173. struct mod_hdcp_output *output)
  174. {
  175. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  176. if (is_hdcp1(hdcp)) {
  177. if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) {
  178. /* TODO - update psp to unify create session failure
  179. * recovery between hdcp1 and 2.
  180. */
  181. mod_hdcp_hdcp1_destroy_session(hdcp);
  182. }
  183. HDCP_TOP_RESET_AUTH_TRACE(hdcp);
  184. memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
  185. memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
  186. set_state_id(hdcp, output, HDCP_INITIALIZED);
  187. } else if (is_hdcp2(hdcp)) {
  188. if (hdcp->auth.trans_input.hdcp2.create_session == PASS) {
  189. status = mod_hdcp_hdcp2_destroy_session(hdcp);
  190. if (status != MOD_HDCP_STATUS_SUCCESS) {
  191. output->callback_needed = 0;
  192. output->watchdog_timer_needed = 0;
  193. goto out;
  194. }
  195. }
  196. HDCP_TOP_RESET_AUTH_TRACE(hdcp);
  197. memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
  198. memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
  199. set_state_id(hdcp, output, HDCP_INITIALIZED);
  200. } else if (is_in_cp_not_desired_state(hdcp)) {
  201. HDCP_TOP_RESET_AUTH_TRACE(hdcp);
  202. memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
  203. memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
  204. set_state_id(hdcp, output, HDCP_INITIALIZED);
  205. }
  206. out:
  207. /* stop callback and watchdog requests from previous authentication*/
  208. output->watchdog_timer_stop = 1;
  209. output->callback_stop = 1;
  210. return status;
  211. }
  212. static enum mod_hdcp_status reset_connection(struct mod_hdcp *hdcp,
  213. struct mod_hdcp_output *output)
  214. {
  215. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  216. memset(output, 0, sizeof(struct mod_hdcp_output));
  217. status = reset_authentication(hdcp, output);
  218. if (status != MOD_HDCP_STATUS_SUCCESS)
  219. goto out;
  220. if (current_state(hdcp) != HDCP_UNINITIALIZED) {
  221. HDCP_TOP_RESET_CONN_TRACE(hdcp);
  222. set_state_id(hdcp, output, HDCP_UNINITIALIZED);
  223. }
  224. memset(&hdcp->connection, 0, sizeof(hdcp->connection));
  225. out:
  226. return status;
  227. }
  228. static enum mod_hdcp_status update_display_adjustments(struct mod_hdcp *hdcp,
  229. struct mod_hdcp_display *display,
  230. struct mod_hdcp_display_adjustment *adj)
  231. {
  232. enum mod_hdcp_status status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
  233. if (is_in_authenticated_states(hdcp) &&
  234. is_dp_mst_hdcp(hdcp) &&
  235. display->adjust.disable == true &&
  236. adj->disable == false) {
  237. display->adjust.disable = false;
  238. if (is_hdcp1(hdcp))
  239. status = mod_hdcp_hdcp1_enable_dp_stream_encryption(hdcp);
  240. else if (is_hdcp2(hdcp))
  241. status = mod_hdcp_hdcp2_enable_dp_stream_encryption(hdcp);
  242. if (status != MOD_HDCP_STATUS_SUCCESS)
  243. display->adjust.disable = true;
  244. }
  245. if (status == MOD_HDCP_STATUS_SUCCESS &&
  246. memcmp(adj, &display->adjust,
  247. sizeof(struct mod_hdcp_display_adjustment)) != 0)
  248. status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
  249. return status;
  250. }
  251. /*
  252. * Implementation of functions in mod_hdcp.h
  253. */
  254. size_t mod_hdcp_get_memory_size(void)
  255. {
  256. return sizeof(struct mod_hdcp);
  257. }
  258. enum mod_hdcp_status mod_hdcp_setup(struct mod_hdcp *hdcp,
  259. struct mod_hdcp_config *config)
  260. {
  261. struct mod_hdcp_output output;
  262. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  263. memset(&output, 0, sizeof(output));
  264. hdcp->config = *config;
  265. HDCP_TOP_INTERFACE_TRACE(hdcp);
  266. status = reset_connection(hdcp, &output);
  267. if (status != MOD_HDCP_STATUS_SUCCESS)
  268. push_error_status(hdcp, status);
  269. return status;
  270. }
  271. enum mod_hdcp_status mod_hdcp_teardown(struct mod_hdcp *hdcp)
  272. {
  273. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  274. struct mod_hdcp_output output;
  275. HDCP_TOP_INTERFACE_TRACE(hdcp);
  276. memset(&output, 0, sizeof(output));
  277. status = reset_connection(hdcp, &output);
  278. if (status == MOD_HDCP_STATUS_SUCCESS)
  279. memset(hdcp, 0, sizeof(struct mod_hdcp));
  280. else
  281. push_error_status(hdcp, status);
  282. return status;
  283. }
  284. enum mod_hdcp_status mod_hdcp_add_display(struct mod_hdcp *hdcp,
  285. struct mod_hdcp_link *link, struct mod_hdcp_display *display,
  286. struct mod_hdcp_output *output)
  287. {
  288. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  289. struct mod_hdcp_display *display_container = NULL;
  290. HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, display->index);
  291. memset(output, 0, sizeof(struct mod_hdcp_output));
  292. /* skip inactive display */
  293. if (display->state != MOD_HDCP_DISPLAY_ACTIVE) {
  294. status = MOD_HDCP_STATUS_SUCCESS;
  295. goto out;
  296. }
  297. /* check existing display container */
  298. if (get_active_display_at_index(hdcp, display->index)) {
  299. status = MOD_HDCP_STATUS_SUCCESS;
  300. goto out;
  301. }
  302. /* find an empty display container */
  303. display_container = get_empty_display_container(hdcp);
  304. if (!display_container) {
  305. status = MOD_HDCP_STATUS_DISPLAY_OUT_OF_BOUND;
  306. goto out;
  307. }
  308. /* reset existing authentication status */
  309. status = reset_authentication(hdcp, output);
  310. if (status != MOD_HDCP_STATUS_SUCCESS)
  311. goto out;
  312. /* reset retry counters */
  313. reset_retry_counts(hdcp);
  314. /* reset error trace */
  315. memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
  316. /* add display to connection */
  317. hdcp->connection.link = *link;
  318. *display_container = *display;
  319. status = mod_hdcp_add_display_to_topology(hdcp, display_container);
  320. if (status != MOD_HDCP_STATUS_SUCCESS)
  321. goto out;
  322. /* request authentication */
  323. if (current_state(hdcp) != HDCP_INITIALIZED)
  324. set_state_id(hdcp, output, HDCP_INITIALIZED);
  325. callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000, output);
  326. out:
  327. if (status != MOD_HDCP_STATUS_SUCCESS)
  328. push_error_status(hdcp, status);
  329. return status;
  330. }
  331. enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp,
  332. uint8_t index, struct mod_hdcp_output *output)
  333. {
  334. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  335. struct mod_hdcp_display *display = NULL;
  336. HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index);
  337. memset(output, 0, sizeof(struct mod_hdcp_output));
  338. /* find display in connection */
  339. display = get_active_display_at_index(hdcp, index);
  340. if (!display) {
  341. status = MOD_HDCP_STATUS_SUCCESS;
  342. goto out;
  343. }
  344. /* stop current authentication */
  345. status = reset_authentication(hdcp, output);
  346. if (status != MOD_HDCP_STATUS_SUCCESS)
  347. goto out;
  348. /* clear retry counters */
  349. reset_retry_counts(hdcp);
  350. /* reset error trace */
  351. memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
  352. /* remove display */
  353. status = mod_hdcp_remove_display_from_topology(hdcp, index);
  354. if (status != MOD_HDCP_STATUS_SUCCESS)
  355. goto out;
  356. memset(display, 0, sizeof(struct mod_hdcp_display));
  357. /* request authentication when connection is not reset */
  358. if (current_state(hdcp) != HDCP_UNINITIALIZED)
  359. callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000,
  360. output);
  361. out:
  362. if (status != MOD_HDCP_STATUS_SUCCESS)
  363. push_error_status(hdcp, status);
  364. return status;
  365. }
  366. enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp,
  367. uint8_t index,
  368. struct mod_hdcp_link_adjustment *link_adjust,
  369. struct mod_hdcp_display_adjustment *display_adjust,
  370. struct mod_hdcp_output *output)
  371. {
  372. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  373. struct mod_hdcp_display *display = NULL;
  374. HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index);
  375. memset(output, 0, sizeof(struct mod_hdcp_output));
  376. /* find display in connection */
  377. display = get_active_display_at_index(hdcp, index);
  378. if (!display) {
  379. status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
  380. goto out;
  381. }
  382. /* skip if no changes */
  383. if (memcmp(link_adjust, &hdcp->connection.link.adjust,
  384. sizeof(struct mod_hdcp_link_adjustment)) == 0 &&
  385. memcmp(display_adjust, &display->adjust,
  386. sizeof(struct mod_hdcp_display_adjustment)) == 0) {
  387. status = MOD_HDCP_STATUS_SUCCESS;
  388. goto out;
  389. }
  390. if (memcmp(link_adjust, &hdcp->connection.link.adjust,
  391. sizeof(struct mod_hdcp_link_adjustment)) == 0 &&
  392. memcmp(display_adjust, &display->adjust,
  393. sizeof(struct mod_hdcp_display_adjustment)) != 0) {
  394. status = update_display_adjustments(hdcp, display, display_adjust);
  395. if (status != MOD_HDCP_STATUS_NOT_IMPLEMENTED)
  396. goto out;
  397. }
  398. /* stop current authentication */
  399. status = reset_authentication(hdcp, output);
  400. if (status != MOD_HDCP_STATUS_SUCCESS)
  401. goto out;
  402. /* clear retry counters */
  403. reset_retry_counts(hdcp);
  404. /* reset error trace */
  405. memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
  406. /* set new adjustment */
  407. hdcp->connection.link.adjust = *link_adjust;
  408. display->adjust = *display_adjust;
  409. /* request authentication when connection is not reset */
  410. if (current_state(hdcp) != HDCP_UNINITIALIZED)
  411. /* wait 100ms to debounce simultaneous updates for different indices */
  412. callback_in_ms(100, output);
  413. out:
  414. if (status != MOD_HDCP_STATUS_SUCCESS)
  415. push_error_status(hdcp, status);
  416. return status;
  417. }
  418. enum mod_hdcp_status mod_hdcp_query_display(struct mod_hdcp *hdcp,
  419. uint8_t index, struct mod_hdcp_display_query *query)
  420. {
  421. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  422. struct mod_hdcp_display *display = NULL;
  423. /* find display in connection */
  424. display = get_active_display_at_index(hdcp, index);
  425. if (!display) {
  426. status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
  427. goto out;
  428. }
  429. /* populate query */
  430. query->link = &hdcp->connection.link;
  431. query->display = display;
  432. query->trace = &hdcp->connection.trace;
  433. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
  434. if (is_display_encryption_enabled(display)) {
  435. if (is_hdcp1(hdcp)) {
  436. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON;
  437. } else if (is_hdcp2(hdcp)) {
  438. if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0)
  439. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON;
  440. else if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1)
  441. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON;
  442. else
  443. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON;
  444. }
  445. } else {
  446. query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
  447. }
  448. out:
  449. return status;
  450. }
  451. enum mod_hdcp_status mod_hdcp_reset_connection(struct mod_hdcp *hdcp,
  452. struct mod_hdcp_output *output)
  453. {
  454. enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
  455. HDCP_TOP_INTERFACE_TRACE(hdcp);
  456. status = reset_connection(hdcp, output);
  457. if (status != MOD_HDCP_STATUS_SUCCESS)
  458. push_error_status(hdcp, status);
  459. return status;
  460. }
  461. enum mod_hdcp_status mod_hdcp_process_event(struct mod_hdcp *hdcp,
  462. enum mod_hdcp_event event, struct mod_hdcp_output *output)
  463. {
  464. enum mod_hdcp_status exec_status, trans_status, reset_status, status;
  465. struct mod_hdcp_event_context event_ctx;
  466. HDCP_EVENT_TRACE(hdcp, event);
  467. memset(output, 0, sizeof(struct mod_hdcp_output));
  468. memset(&event_ctx, 0, sizeof(struct mod_hdcp_event_context));
  469. event_ctx.event = event;
  470. /* execute and transition */
  471. exec_status = execution(hdcp, &event_ctx, &hdcp->auth.trans_input);
  472. trans_status = transition(
  473. hdcp, &event_ctx, &hdcp->auth.trans_input, output);
  474. if (trans_status == MOD_HDCP_STATUS_SUCCESS) {
  475. status = MOD_HDCP_STATUS_SUCCESS;
  476. } else if (exec_status == MOD_HDCP_STATUS_SUCCESS) {
  477. status = MOD_HDCP_STATUS_INTERNAL_POLICY_FAILURE;
  478. push_error_status(hdcp, status);
  479. } else {
  480. status = exec_status;
  481. push_error_status(hdcp, status);
  482. }
  483. /* reset authentication if needed */
  484. if (trans_status == MOD_HDCP_STATUS_RESET_NEEDED) {
  485. mod_hdcp_log_ddc_trace(hdcp);
  486. reset_status = reset_authentication(hdcp, output);
  487. if (reset_status != MOD_HDCP_STATUS_SUCCESS)
  488. push_error_status(hdcp, reset_status);
  489. }
  490. /* Clear CP_IRQ status if needed */
  491. if (event_ctx.event == MOD_HDCP_EVENT_CPIRQ) {
  492. status = mod_hdcp_clear_cp_irq_status(hdcp);
  493. if (status != MOD_HDCP_STATUS_SUCCESS)
  494. push_error_status(hdcp, status);
  495. }
  496. return status;
  497. }
  498. enum mod_hdcp_operation_mode mod_hdcp_signal_type_to_operation_mode(
  499. enum signal_type signal)
  500. {
  501. enum mod_hdcp_operation_mode mode = MOD_HDCP_MODE_OFF;
  502. switch (signal) {
  503. case SIGNAL_TYPE_DVI_SINGLE_LINK:
  504. case SIGNAL_TYPE_HDMI_TYPE_A:
  505. mode = MOD_HDCP_MODE_DEFAULT;
  506. break;
  507. case SIGNAL_TYPE_EDP:
  508. case SIGNAL_TYPE_DISPLAY_PORT:
  509. case SIGNAL_TYPE_DISPLAY_PORT_MST:
  510. mode = MOD_HDCP_MODE_DP;
  511. break;
  512. default:
  513. break;
  514. }
  515. return mode;
  516. }