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 | |
26 | #include "hdcp.h" |
27 | |
28 | static void push_error_status(struct mod_hdcp *hdcp, |
29 | enum mod_hdcp_status status) |
30 | { |
31 | struct mod_hdcp_trace *trace = &hdcp->connection.trace; |
32 | |
33 | if (trace->error_count < MAX_NUM_OF_ERROR_TRACE) { |
34 | trace->errors[trace->error_count].status = status; |
35 | trace->errors[trace->error_count].state_id = hdcp->state.id; |
36 | trace->error_count++; |
37 | HDCP_ERROR_TRACE(hdcp, status); |
38 | } |
39 | |
40 | if (is_hdcp1(hdcp)) { |
41 | hdcp->connection.hdcp1_retry_count++; |
42 | if (hdcp->connection.hdcp1_retry_count == MAX_NUM_OF_ATTEMPTS) |
43 | hdcp->connection.link.adjust.hdcp1.disable = 1; |
44 | } else if (is_hdcp2(hdcp)) { |
45 | hdcp->connection.hdcp2_retry_count++; |
46 | if (hdcp->connection.hdcp2_retry_count == MAX_NUM_OF_ATTEMPTS) |
47 | hdcp->connection.link.adjust.hdcp2.disable = 1; |
48 | } |
49 | } |
50 | |
51 | static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp) |
52 | { |
53 | int i, is_auth_needed = 0; |
54 | |
55 | /* if all displays on the link don't need authentication, |
56 | * hdcp is not desired |
57 | */ |
58 | for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { |
59 | if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && |
60 | hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) { |
61 | is_auth_needed = 1; |
62 | break; |
63 | } |
64 | } |
65 | |
66 | return is_auth_needed && |
67 | !hdcp->connection.link.adjust.hdcp1.disable && |
68 | !hdcp->connection.is_hdcp1_revoked; |
69 | } |
70 | |
71 | static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp) |
72 | { |
73 | int i, is_auth_needed = 0; |
74 | |
75 | /* if all displays on the link don't need authentication, |
76 | * hdcp is not desired |
77 | */ |
78 | for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { |
79 | if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && |
80 | hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) { |
81 | is_auth_needed = 1; |
82 | break; |
83 | } |
84 | } |
85 | |
86 | return is_auth_needed && |
87 | !hdcp->connection.link.adjust.hdcp2.disable && |
88 | !hdcp->connection.is_hdcp2_revoked; |
89 | } |
90 | |
91 | static enum mod_hdcp_status execution(struct mod_hdcp *hdcp, |
92 | struct mod_hdcp_event_context *event_ctx, |
93 | union mod_hdcp_transition_input *input) |
94 | { |
95 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
96 | |
97 | if (is_in_initialized_state(hdcp)) { |
98 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
99 | event_ctx->unexpected_event = 1; |
100 | goto out; |
101 | } |
102 | /* initialize transition input */ |
103 | memset(input, 0, sizeof(union mod_hdcp_transition_input)); |
104 | } else if (is_in_cp_not_desired_state(hdcp)) { |
105 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
106 | event_ctx->unexpected_event = 1; |
107 | goto out; |
108 | } |
109 | } else if (is_in_hdcp1_states(hdcp)) { |
110 | status = mod_hdcp_hdcp1_execution(hdcp, event_ctx, input: &input->hdcp1); |
111 | } else if (is_in_hdcp1_dp_states(hdcp)) { |
112 | status = mod_hdcp_hdcp1_dp_execution(hdcp, |
113 | event_ctx, input: &input->hdcp1); |
114 | } else if (is_in_hdcp2_states(hdcp)) { |
115 | status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, input: &input->hdcp2); |
116 | } else if (is_in_hdcp2_dp_states(hdcp)) { |
117 | status = mod_hdcp_hdcp2_dp_execution(hdcp, |
118 | event_ctx, input: &input->hdcp2); |
119 | } else { |
120 | event_ctx->unexpected_event = 1; |
121 | goto out; |
122 | } |
123 | out: |
124 | return status; |
125 | } |
126 | |
127 | static enum mod_hdcp_status transition(struct mod_hdcp *hdcp, |
128 | struct mod_hdcp_event_context *event_ctx, |
129 | union mod_hdcp_transition_input *input, |
130 | struct mod_hdcp_output *output) |
131 | { |
132 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
133 | |
134 | if (event_ctx->unexpected_event) |
135 | goto out; |
136 | |
137 | if (is_in_initialized_state(hdcp)) { |
138 | if (is_dp_hdcp(hdcp)) |
139 | if (is_cp_desired_hdcp2(hdcp)) { |
140 | callback_in_ms(time: 0, output); |
141 | set_state_id(hdcp, output, id: D2_A0_DETERMINE_RX_HDCP_CAPABLE); |
142 | } else if (is_cp_desired_hdcp1(hdcp)) { |
143 | callback_in_ms(time: 0, output); |
144 | set_state_id(hdcp, output, id: D1_A0_DETERMINE_RX_HDCP_CAPABLE); |
145 | } else { |
146 | callback_in_ms(time: 0, output); |
147 | set_state_id(hdcp, output, id: HDCP_CP_NOT_DESIRED); |
148 | set_auth_complete(hdcp, output); |
149 | } |
150 | else if (is_hdmi_dvi_sl_hdcp(hdcp)) |
151 | if (is_cp_desired_hdcp2(hdcp)) { |
152 | callback_in_ms(time: 0, output); |
153 | set_state_id(hdcp, output, id: H2_A0_KNOWN_HDCP2_CAPABLE_RX); |
154 | } else if (is_cp_desired_hdcp1(hdcp)) { |
155 | callback_in_ms(time: 0, output); |
156 | set_state_id(hdcp, output, id: H1_A0_WAIT_FOR_ACTIVE_RX); |
157 | } else { |
158 | callback_in_ms(time: 0, output); |
159 | set_state_id(hdcp, output, id: HDCP_CP_NOT_DESIRED); |
160 | set_auth_complete(hdcp, output); |
161 | } |
162 | else { |
163 | callback_in_ms(time: 0, output); |
164 | set_state_id(hdcp, output, id: HDCP_CP_NOT_DESIRED); |
165 | set_auth_complete(hdcp, output); |
166 | } |
167 | } else if (is_in_cp_not_desired_state(hdcp)) { |
168 | increment_stay_counter(hdcp); |
169 | } else if (is_in_hdcp1_states(hdcp)) { |
170 | status = mod_hdcp_hdcp1_transition(hdcp, |
171 | event_ctx, input: &input->hdcp1, output); |
172 | } else if (is_in_hdcp1_dp_states(hdcp)) { |
173 | status = mod_hdcp_hdcp1_dp_transition(hdcp, |
174 | event_ctx, input: &input->hdcp1, output); |
175 | } else if (is_in_hdcp2_states(hdcp)) { |
176 | status = mod_hdcp_hdcp2_transition(hdcp, |
177 | event_ctx, input: &input->hdcp2, output); |
178 | } else if (is_in_hdcp2_dp_states(hdcp)) { |
179 | status = mod_hdcp_hdcp2_dp_transition(hdcp, |
180 | event_ctx, input: &input->hdcp2, output); |
181 | } else { |
182 | status = MOD_HDCP_STATUS_INVALID_STATE; |
183 | } |
184 | out: |
185 | return status; |
186 | } |
187 | |
188 | static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp, |
189 | struct mod_hdcp_output *output) |
190 | { |
191 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
192 | |
193 | if (is_hdcp1(hdcp)) { |
194 | if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) { |
195 | /* TODO - update psp to unify create session failure |
196 | * recovery between hdcp1 and 2. |
197 | */ |
198 | mod_hdcp_hdcp1_destroy_session(hdcp); |
199 | |
200 | } |
201 | |
202 | HDCP_TOP_RESET_AUTH_TRACE(hdcp); |
203 | memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); |
204 | memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); |
205 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
206 | } else if (is_hdcp2(hdcp)) { |
207 | if (hdcp->auth.trans_input.hdcp2.create_session == PASS) { |
208 | status = mod_hdcp_hdcp2_destroy_session(hdcp); |
209 | if (status != MOD_HDCP_STATUS_SUCCESS) { |
210 | output->callback_needed = 0; |
211 | output->watchdog_timer_needed = 0; |
212 | goto out; |
213 | } |
214 | } |
215 | |
216 | HDCP_TOP_RESET_AUTH_TRACE(hdcp); |
217 | memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); |
218 | memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); |
219 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
220 | } else if (is_in_cp_not_desired_state(hdcp)) { |
221 | HDCP_TOP_RESET_AUTH_TRACE(hdcp); |
222 | memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); |
223 | memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); |
224 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
225 | } |
226 | |
227 | out: |
228 | /* stop callback and watchdog requests from previous authentication*/ |
229 | output->watchdog_timer_stop = 1; |
230 | output->callback_stop = 1; |
231 | return status; |
232 | } |
233 | |
234 | static enum mod_hdcp_status reset_connection(struct mod_hdcp *hdcp, |
235 | struct mod_hdcp_output *output) |
236 | { |
237 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
238 | |
239 | memset(output, 0, sizeof(struct mod_hdcp_output)); |
240 | |
241 | status = reset_authentication(hdcp, output); |
242 | if (status != MOD_HDCP_STATUS_SUCCESS) |
243 | goto out; |
244 | |
245 | if (current_state(hdcp) != HDCP_UNINITIALIZED) { |
246 | HDCP_TOP_RESET_CONN_TRACE(hdcp); |
247 | set_state_id(hdcp, output, id: HDCP_UNINITIALIZED); |
248 | } |
249 | memset(&hdcp->connection, 0, sizeof(hdcp->connection)); |
250 | out: |
251 | return status; |
252 | } |
253 | |
254 | static enum mod_hdcp_status update_display_adjustments(struct mod_hdcp *hdcp, |
255 | struct mod_hdcp_display *display, |
256 | struct mod_hdcp_display_adjustment *adj) |
257 | { |
258 | enum mod_hdcp_status status = MOD_HDCP_STATUS_NOT_IMPLEMENTED; |
259 | |
260 | if (is_in_authenticated_states(hdcp) && |
261 | is_dp_mst_hdcp(hdcp) && |
262 | display->adjust.disable == true && |
263 | adj->disable == false) { |
264 | display->adjust.disable = false; |
265 | if (is_hdcp1(hdcp)) |
266 | status = mod_hdcp_hdcp1_enable_dp_stream_encryption(hdcp); |
267 | else if (is_hdcp2(hdcp)) |
268 | status = mod_hdcp_hdcp2_enable_dp_stream_encryption(hdcp); |
269 | |
270 | if (status != MOD_HDCP_STATUS_SUCCESS) |
271 | display->adjust.disable = true; |
272 | } |
273 | |
274 | if (status == MOD_HDCP_STATUS_SUCCESS && |
275 | memcmp(p: adj, q: &display->adjust, |
276 | size: sizeof(struct mod_hdcp_display_adjustment)) != 0) |
277 | status = MOD_HDCP_STATUS_NOT_IMPLEMENTED; |
278 | |
279 | return status; |
280 | } |
281 | /* |
282 | * Implementation of functions in mod_hdcp.h |
283 | */ |
284 | size_t mod_hdcp_get_memory_size(void) |
285 | { |
286 | return sizeof(struct mod_hdcp); |
287 | } |
288 | |
289 | enum mod_hdcp_status mod_hdcp_setup(struct mod_hdcp *hdcp, |
290 | struct mod_hdcp_config *config) |
291 | { |
292 | struct mod_hdcp_output output; |
293 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
294 | |
295 | memset(&output, 0, sizeof(output)); |
296 | hdcp->config = *config; |
297 | HDCP_TOP_INTERFACE_TRACE(hdcp); |
298 | status = reset_connection(hdcp, output: &output); |
299 | if (status != MOD_HDCP_STATUS_SUCCESS) |
300 | push_error_status(hdcp, status); |
301 | return status; |
302 | } |
303 | |
304 | enum mod_hdcp_status mod_hdcp_teardown(struct mod_hdcp *hdcp) |
305 | { |
306 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
307 | struct mod_hdcp_output output; |
308 | |
309 | HDCP_TOP_INTERFACE_TRACE(hdcp); |
310 | memset(&output, 0, sizeof(output)); |
311 | status = reset_connection(hdcp, output: &output); |
312 | if (status == MOD_HDCP_STATUS_SUCCESS) |
313 | memset(hdcp, 0, sizeof(struct mod_hdcp)); |
314 | else |
315 | push_error_status(hdcp, status); |
316 | return status; |
317 | } |
318 | |
319 | enum mod_hdcp_status mod_hdcp_add_display(struct mod_hdcp *hdcp, |
320 | struct mod_hdcp_link *link, struct mod_hdcp_display *display, |
321 | struct mod_hdcp_output *output) |
322 | { |
323 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
324 | struct mod_hdcp_display *display_container = NULL; |
325 | |
326 | HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, display->index); |
327 | memset(output, 0, sizeof(struct mod_hdcp_output)); |
328 | |
329 | /* skip inactive display */ |
330 | if (display->state != MOD_HDCP_DISPLAY_ACTIVE) { |
331 | status = MOD_HDCP_STATUS_SUCCESS; |
332 | goto out; |
333 | } |
334 | |
335 | /* check existing display container */ |
336 | if (get_active_display_at_index(hdcp, index: display->index)) { |
337 | status = MOD_HDCP_STATUS_SUCCESS; |
338 | goto out; |
339 | } |
340 | |
341 | /* find an empty display container */ |
342 | display_container = get_empty_display_container(hdcp); |
343 | if (!display_container) { |
344 | status = MOD_HDCP_STATUS_DISPLAY_OUT_OF_BOUND; |
345 | goto out; |
346 | } |
347 | |
348 | /* reset existing authentication status */ |
349 | status = reset_authentication(hdcp, output); |
350 | if (status != MOD_HDCP_STATUS_SUCCESS) |
351 | goto out; |
352 | |
353 | /* reset retry counters */ |
354 | reset_retry_counts(hdcp); |
355 | |
356 | /* reset error trace */ |
357 | memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace)); |
358 | |
359 | /* add display to connection */ |
360 | hdcp->connection.link = *link; |
361 | *display_container = *display; |
362 | status = mod_hdcp_add_display_to_topology(hdcp, display: display_container); |
363 | |
364 | if (status != MOD_HDCP_STATUS_SUCCESS) |
365 | goto out; |
366 | |
367 | /* request authentication */ |
368 | if (current_state(hdcp) != HDCP_INITIALIZED) |
369 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
370 | callback_in_ms(time: hdcp->connection.link.adjust.auth_delay * 1000, output); |
371 | out: |
372 | if (status != MOD_HDCP_STATUS_SUCCESS) |
373 | push_error_status(hdcp, status); |
374 | |
375 | return status; |
376 | } |
377 | |
378 | enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp, |
379 | uint8_t index, struct mod_hdcp_output *output) |
380 | { |
381 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
382 | struct mod_hdcp_display *display = NULL; |
383 | |
384 | HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index); |
385 | memset(output, 0, sizeof(struct mod_hdcp_output)); |
386 | |
387 | /* find display in connection */ |
388 | display = get_active_display_at_index(hdcp, index); |
389 | if (!display) { |
390 | status = MOD_HDCP_STATUS_SUCCESS; |
391 | goto out; |
392 | } |
393 | |
394 | /* stop current authentication */ |
395 | status = reset_authentication(hdcp, output); |
396 | if (status != MOD_HDCP_STATUS_SUCCESS) |
397 | goto out; |
398 | |
399 | /* clear retry counters */ |
400 | reset_retry_counts(hdcp); |
401 | |
402 | /* reset error trace */ |
403 | memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace)); |
404 | |
405 | /* remove display */ |
406 | status = mod_hdcp_remove_display_from_topology(hdcp, index); |
407 | if (status != MOD_HDCP_STATUS_SUCCESS) |
408 | goto out; |
409 | memset(display, 0, sizeof(struct mod_hdcp_display)); |
410 | |
411 | /* request authentication when connection is not reset */ |
412 | if (current_state(hdcp) != HDCP_UNINITIALIZED) |
413 | callback_in_ms(time: hdcp->connection.link.adjust.auth_delay * 1000, |
414 | output); |
415 | out: |
416 | if (status != MOD_HDCP_STATUS_SUCCESS) |
417 | push_error_status(hdcp, status); |
418 | return status; |
419 | } |
420 | |
421 | enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp, |
422 | uint8_t index, |
423 | struct mod_hdcp_link_adjustment *link_adjust, |
424 | struct mod_hdcp_display_adjustment *display_adjust, |
425 | struct mod_hdcp_output *output) |
426 | { |
427 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
428 | struct mod_hdcp_display *display = NULL; |
429 | |
430 | HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index); |
431 | memset(output, 0, sizeof(struct mod_hdcp_output)); |
432 | |
433 | /* find display in connection */ |
434 | display = get_active_display_at_index(hdcp, index); |
435 | if (!display) { |
436 | status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; |
437 | goto out; |
438 | } |
439 | |
440 | /* skip if no changes */ |
441 | if (memcmp(p: link_adjust, q: &hdcp->connection.link.adjust, |
442 | size: sizeof(struct mod_hdcp_link_adjustment)) == 0 && |
443 | memcmp(p: display_adjust, q: &display->adjust, |
444 | size: sizeof(struct mod_hdcp_display_adjustment)) == 0) { |
445 | status = MOD_HDCP_STATUS_SUCCESS; |
446 | goto out; |
447 | } |
448 | |
449 | if (memcmp(p: link_adjust, q: &hdcp->connection.link.adjust, |
450 | size: sizeof(struct mod_hdcp_link_adjustment)) == 0 && |
451 | memcmp(p: display_adjust, q: &display->adjust, |
452 | size: sizeof(struct mod_hdcp_display_adjustment)) != 0) { |
453 | status = update_display_adjustments(hdcp, display, adj: display_adjust); |
454 | if (status != MOD_HDCP_STATUS_NOT_IMPLEMENTED) |
455 | goto out; |
456 | } |
457 | |
458 | /* stop current authentication */ |
459 | status = reset_authentication(hdcp, output); |
460 | if (status != MOD_HDCP_STATUS_SUCCESS) |
461 | goto out; |
462 | |
463 | /* clear retry counters */ |
464 | reset_retry_counts(hdcp); |
465 | |
466 | /* reset error trace */ |
467 | memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace)); |
468 | |
469 | /* set new adjustment */ |
470 | hdcp->connection.link.adjust = *link_adjust; |
471 | display->adjust = *display_adjust; |
472 | |
473 | /* request authentication when connection is not reset */ |
474 | if (current_state(hdcp) != HDCP_UNINITIALIZED) |
475 | /* wait 100ms to debounce simultaneous updates for different indices */ |
476 | callback_in_ms(time: 100, output); |
477 | |
478 | out: |
479 | if (status != MOD_HDCP_STATUS_SUCCESS) |
480 | push_error_status(hdcp, status); |
481 | return status; |
482 | } |
483 | |
484 | enum mod_hdcp_status mod_hdcp_query_display(struct mod_hdcp *hdcp, |
485 | uint8_t index, struct mod_hdcp_display_query *query) |
486 | { |
487 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
488 | struct mod_hdcp_display *display = NULL; |
489 | |
490 | /* find display in connection */ |
491 | display = get_active_display_at_index(hdcp, index); |
492 | if (!display) { |
493 | status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; |
494 | goto out; |
495 | } |
496 | |
497 | /* populate query */ |
498 | query->link = &hdcp->connection.link; |
499 | query->display = display; |
500 | query->trace = &hdcp->connection.trace; |
501 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; |
502 | |
503 | if (is_display_encryption_enabled(display)) { |
504 | if (is_hdcp1(hdcp)) { |
505 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON; |
506 | } else if (is_hdcp2(hdcp)) { |
507 | if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0) |
508 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON; |
509 | else if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1) |
510 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON; |
511 | else |
512 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON; |
513 | } |
514 | } else { |
515 | query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; |
516 | } |
517 | |
518 | out: |
519 | return status; |
520 | } |
521 | |
522 | enum mod_hdcp_status mod_hdcp_reset_connection(struct mod_hdcp *hdcp, |
523 | struct mod_hdcp_output *output) |
524 | { |
525 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
526 | |
527 | HDCP_TOP_INTERFACE_TRACE(hdcp); |
528 | status = reset_connection(hdcp, output); |
529 | if (status != MOD_HDCP_STATUS_SUCCESS) |
530 | push_error_status(hdcp, status); |
531 | |
532 | return status; |
533 | } |
534 | |
535 | enum mod_hdcp_status mod_hdcp_process_event(struct mod_hdcp *hdcp, |
536 | enum mod_hdcp_event event, struct mod_hdcp_output *output) |
537 | { |
538 | enum mod_hdcp_status exec_status, trans_status, reset_status, status; |
539 | struct mod_hdcp_event_context event_ctx; |
540 | |
541 | HDCP_EVENT_TRACE(hdcp, event); |
542 | memset(output, 0, sizeof(struct mod_hdcp_output)); |
543 | memset(&event_ctx, 0, sizeof(struct mod_hdcp_event_context)); |
544 | event_ctx.event = event; |
545 | |
546 | /* execute and transition */ |
547 | exec_status = execution(hdcp, event_ctx: &event_ctx, input: &hdcp->auth.trans_input); |
548 | trans_status = transition( |
549 | hdcp, event_ctx: &event_ctx, input: &hdcp->auth.trans_input, output); |
550 | if (trans_status == MOD_HDCP_STATUS_SUCCESS) { |
551 | status = MOD_HDCP_STATUS_SUCCESS; |
552 | } else if (exec_status == MOD_HDCP_STATUS_SUCCESS) { |
553 | status = MOD_HDCP_STATUS_INTERNAL_POLICY_FAILURE; |
554 | push_error_status(hdcp, status); |
555 | } else { |
556 | status = exec_status; |
557 | push_error_status(hdcp, status); |
558 | } |
559 | |
560 | /* reset authentication if needed */ |
561 | if (trans_status == MOD_HDCP_STATUS_RESET_NEEDED) { |
562 | mod_hdcp_log_ddc_trace(hdcp); |
563 | reset_status = reset_authentication(hdcp, output); |
564 | if (reset_status != MOD_HDCP_STATUS_SUCCESS) |
565 | push_error_status(hdcp, status: reset_status); |
566 | } |
567 | |
568 | /* Clear CP_IRQ status if needed */ |
569 | if (event_ctx.event == MOD_HDCP_EVENT_CPIRQ) { |
570 | status = mod_hdcp_clear_cp_irq_status(hdcp); |
571 | if (status != MOD_HDCP_STATUS_SUCCESS) |
572 | push_error_status(hdcp, status); |
573 | } |
574 | |
575 | return status; |
576 | } |
577 | |
578 | enum mod_hdcp_operation_mode mod_hdcp_signal_type_to_operation_mode( |
579 | enum signal_type signal) |
580 | { |
581 | enum mod_hdcp_operation_mode mode = MOD_HDCP_MODE_OFF; |
582 | |
583 | switch (signal) { |
584 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
585 | case SIGNAL_TYPE_HDMI_TYPE_A: |
586 | mode = MOD_HDCP_MODE_DEFAULT; |
587 | break; |
588 | case SIGNAL_TYPE_EDP: |
589 | case SIGNAL_TYPE_DISPLAY_PORT: |
590 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
591 | mode = MOD_HDCP_MODE_DP; |
592 | break; |
593 | default: |
594 | break; |
595 | } |
596 | |
597 | return mode; |
598 | } |
599 | |