Commit | Line | Data |
---|---|---|
4c283fda BL |
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 | ||
51466b3f BL |
40 | if (is_hdcp1(hdcp)) { |
41 | hdcp->connection.hdcp1_retry_count++; | |
40ef288f WL |
42 | if (hdcp->connection.hdcp1_retry_count == MAX_NUM_OF_ATTEMPTS) |
43 | hdcp->connection.link.adjust.hdcp1.disable = 1; | |
51466b3f BL |
44 | } else if (is_hdcp2(hdcp)) { |
45 | hdcp->connection.hdcp2_retry_count++; | |
40ef288f WL |
46 | if (hdcp->connection.hdcp2_retry_count == MAX_NUM_OF_ATTEMPTS) |
47 | hdcp->connection.link.adjust.hdcp2.disable = 1; | |
51466b3f | 48 | } |
4c283fda BL |
49 | } |
50 | ||
51 | static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp) | |
52 | { | |
51466b3f | 53 | int i, is_auth_needed = 0; |
4c283fda | 54 | |
51466b3f BL |
55 | /* if all displays on the link don't need authentication, |
56 | * hdcp is not desired | |
57 | */ | |
4c283fda | 58 | for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { |
a09f8e29 | 59 | if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && |
4fe1fdcc | 60 | hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) { |
51466b3f | 61 | is_auth_needed = 1; |
4c283fda BL |
62 | break; |
63 | } | |
64 | } | |
65 | ||
40ef288f | 66 | return is_auth_needed && |
3744ee2c WL |
67 | !hdcp->connection.link.adjust.hdcp1.disable && |
68 | !hdcp->connection.is_hdcp1_revoked; | |
51466b3f BL |
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++) { | |
a09f8e29 | 79 | if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && |
4fe1fdcc | 80 | hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) { |
51466b3f BL |
81 | is_auth_needed = 1; |
82 | break; | |
83 | } | |
84 | } | |
85 | ||
40ef288f | 86 | return is_auth_needed && |
51466b3f BL |
87 | !hdcp->connection.link.adjust.hdcp2.disable && |
88 | !hdcp->connection.is_hdcp2_revoked; | |
4c283fda BL |
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 | } | |
4c283fda BL |
109 | } else if (is_in_hdcp1_states(hdcp)) { |
110 | status = mod_hdcp_hdcp1_execution(hdcp, event_ctx, &input->hdcp1); | |
111 | } else if (is_in_hdcp1_dp_states(hdcp)) { | |
112 | status = mod_hdcp_hdcp1_dp_execution(hdcp, | |
113 | event_ctx, &input->hdcp1); | |
51466b3f BL |
114 | } else if (is_in_hdcp2_states(hdcp)) { |
115 | status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2); | |
116 | } else if (is_in_hdcp2_dp_states(hdcp)) { | |
117 | status = mod_hdcp_hdcp2_dp_execution(hdcp, | |
118 | event_ctx, &input->hdcp2); | |
1450d237 WL |
119 | } else { |
120 | event_ctx->unexpected_event = 1; | |
121 | goto out; | |
4c283fda BL |
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)) | |
51466b3f BL |
139 | if (is_cp_desired_hdcp2(hdcp)) { |
140 | callback_in_ms(0, output); | |
141 | set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE); | |
142 | } else if (is_cp_desired_hdcp1(hdcp)) { | |
4c283fda BL |
143 | callback_in_ms(0, output); |
144 | set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE); | |
145 | } else { | |
146 | callback_in_ms(0, output); | |
147 | set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); | |
0a95fab3 | 148 | set_auth_complete(hdcp, output); |
4c283fda BL |
149 | } |
150 | else if (is_hdmi_dvi_sl_hdcp(hdcp)) | |
51466b3f BL |
151 | if (is_cp_desired_hdcp2(hdcp)) { |
152 | callback_in_ms(0, output); | |
153 | set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX); | |
154 | } else if (is_cp_desired_hdcp1(hdcp)) { | |
4c283fda BL |
155 | callback_in_ms(0, output); |
156 | set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX); | |
157 | } else { | |
158 | callback_in_ms(0, output); | |
159 | set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); | |
0a95fab3 | 160 | set_auth_complete(hdcp, output); |
4c283fda BL |
161 | } |
162 | else { | |
163 | callback_in_ms(0, output); | |
164 | set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); | |
0a95fab3 | 165 | set_auth_complete(hdcp, output); |
4c283fda BL |
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->hdcp1, output); | |
172 | } else if (is_in_hdcp1_dp_states(hdcp)) { | |
173 | status = mod_hdcp_hdcp1_dp_transition(hdcp, | |
174 | event_ctx, &input->hdcp1, output); | |
51466b3f BL |
175 | } else if (is_in_hdcp2_states(hdcp)) { |
176 | status = mod_hdcp_hdcp2_transition(hdcp, | |
177 | event_ctx, &input->hdcp2, output); | |
178 | } else if (is_in_hdcp2_dp_states(hdcp)) { | |
179 | status = mod_hdcp_hdcp2_dp_transition(hdcp, | |
180 | event_ctx, &input->hdcp2, output); | |
4c283fda BL |
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)) { | |
51466b3f BL |
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 | */ | |
4c283fda BL |
198 | mod_hdcp_hdcp1_destroy_session(hdcp); |
199 | ||
51466b3f | 200 | } |
9124ee78 | 201 | |
4c283fda BL |
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, HDCP_INITIALIZED); | |
51466b3f BL |
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 | } | |
9124ee78 | 215 | |
51466b3f BL |
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, HDCP_INITIALIZED); | |
4c283fda | 220 | } else if (is_in_cp_not_desired_state(hdcp)) { |
4c283fda BL |
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, 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, HDCP_UNINITIALIZED); | |
248 | } | |
249 | memset(&hdcp->connection, 0, sizeof(hdcp->connection)); | |
250 | out: | |
251 | return status; | |
252 | } | |
253 | ||
4268d081 AO |
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(adj, &display->adjust, | |
276 | sizeof(struct mod_hdcp_display_adjustment)) != 0) | |
277 | status = MOD_HDCP_STATUS_NOT_IMPLEMENTED; | |
278 | ||
279 | return status; | |
280 | } | |
4c283fda BL |
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 | ||
4c283fda BL |
295 | memset(&output, 0, sizeof(output)); |
296 | hdcp->config = *config; | |
297 | HDCP_TOP_INTERFACE_TRACE(hdcp); | |
298 | status = reset_connection(hdcp, &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); | |
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, 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 | ||
4c283fda BL |
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 | ||
9124ee78 WL |
359 | /* add display to connection */ |
360 | hdcp->connection.link = *link; | |
361 | *display_container = *display; | |
2deade5e IZ |
362 | status = mod_hdcp_add_display_to_topology(hdcp, display_container); |
363 | ||
9124ee78 WL |
364 | if (status != MOD_HDCP_STATUS_SUCCESS) |
365 | goto out; | |
366 | ||
4c283fda BL |
367 | /* request authentication */ |
368 | if (current_state(hdcp) != HDCP_INITIALIZED) | |
369 | set_state_id(hdcp, output, HDCP_INITIALIZED); | |
370 | callback_in_ms(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 | ||
4c283fda BL |
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 | ||
9124ee78 WL |
405 | /* remove display */ |
406 | status = mod_hdcp_remove_display_from_topology(hdcp, index); | |
407 | if (status != MOD_HDCP_STATUS_SUCCESS) | |
408 | goto out; | |
2deade5e | 409 | memset(display, 0, sizeof(struct mod_hdcp_display)); |
9124ee78 | 410 | |
a09f8e29 IZ |
411 | /* request authentication when connection is not reset */ |
412 | if (current_state(hdcp) != HDCP_UNINITIALIZED) | |
4c283fda BL |
413 | callback_in_ms(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 | ||
4268d081 | 421 | enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp, |
40ef288f WL |
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(link_adjust, &hdcp->connection.link.adjust, | |
442 | sizeof(struct mod_hdcp_link_adjustment)) == 0 && | |
443 | memcmp(display_adjust, &display->adjust, | |
444 | sizeof(struct mod_hdcp_display_adjustment)) == 0) { | |
445 | status = MOD_HDCP_STATUS_SUCCESS; | |
446 | goto out; | |
447 | } | |
448 | ||
4268d081 AO |
449 | if (memcmp(link_adjust, &hdcp->connection.link.adjust, |
450 | sizeof(struct mod_hdcp_link_adjustment)) == 0 && | |
451 | memcmp(display_adjust, &display->adjust, | |
452 | sizeof(struct mod_hdcp_display_adjustment)) != 0) { | |
453 | status = update_display_adjustments(hdcp, display, display_adjust); | |
454 | if (status != MOD_HDCP_STATUS_NOT_IMPLEMENTED) | |
455 | goto out; | |
456 | } | |
457 | ||
40ef288f WL |
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(100, output); | |
477 | ||
478 | out: | |
479 | if (status != MOD_HDCP_STATUS_SUCCESS) | |
480 | push_error_status(hdcp, status); | |
481 | return status; | |
482 | } | |
483 | ||
4c283fda BL |
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 | ||
45375a50 BL |
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 | } | |
4c283fda BL |
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, &hdcp->auth.trans_input); | |
548 | trans_status = transition( | |
549 | hdcp, &event_ctx, &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) { | |
0a95fab3 | 562 | mod_hdcp_log_ddc_trace(hdcp); |
4c283fda BL |
563 | reset_status = reset_authentication(hdcp, output); |
564 | if (reset_status != MOD_HDCP_STATUS_SUCCESS) | |
565 | push_error_status(hdcp, reset_status); | |
566 | } | |
958000cb HT |
567 | |
568 | /* Clear CP_IRQ status if needed */ | |
5cd04c48 | 569 | if (event_ctx.event == MOD_HDCP_EVENT_CPIRQ) { |
958000cb HT |
570 | status = mod_hdcp_clear_cp_irq_status(hdcp); |
571 | if (status != MOD_HDCP_STATUS_SUCCESS) | |
572 | push_error_status(hdcp, status); | |
573 | } | |
574 | ||
4c283fda BL |
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: | |
4c283fda | 590 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
b6a1a0e7 | 591 | mode = MOD_HDCP_MODE_DP; |
4c283fda BL |
592 | break; |
593 | default: | |
594 | break; | |
2fd4f169 | 595 | } |
4c283fda BL |
596 | |
597 | return mode; | |
598 | } |