1 | /* |
2 | * Copyright 2018 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 | enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp, |
29 | struct mod_hdcp_event_context *event_ctx, |
30 | struct mod_hdcp_transition_input_hdcp2 *input, |
31 | struct mod_hdcp_output *output) |
32 | { |
33 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
34 | struct mod_hdcp_connection *conn = &hdcp->connection; |
35 | struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust; |
36 | |
37 | switch (current_state(hdcp)) { |
38 | case H2_A0_KNOWN_HDCP2_CAPABLE_RX: |
39 | if (input->hdcp2version_read != PASS || |
40 | input->hdcp2_capable_check != PASS) { |
41 | adjust->hdcp2.disable = 1; |
42 | callback_in_ms(time: 0, output); |
43 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
44 | } else { |
45 | callback_in_ms(time: 0, output); |
46 | set_state_id(hdcp, output, id: H2_A1_SEND_AKE_INIT); |
47 | } |
48 | break; |
49 | case H2_A1_SEND_AKE_INIT: |
50 | if (input->create_session != PASS || |
51 | input->ake_init_prepare != PASS) { |
52 | /* out of sync with psp state */ |
53 | adjust->hdcp2.disable = 1; |
54 | fail_and_restart_in_ms(time: 0, status: &status, output); |
55 | break; |
56 | } else if (input->ake_init_write != PASS) { |
57 | fail_and_restart_in_ms(time: 0, status: &status, output); |
58 | break; |
59 | } |
60 | set_watchdog_in_ms(hdcp, time: 100, output); |
61 | callback_in_ms(time: 0, output); |
62 | set_state_id(hdcp, output, id: H2_A1_VALIDATE_AKE_CERT); |
63 | break; |
64 | case H2_A1_VALIDATE_AKE_CERT: |
65 | if (input->ake_cert_available != PASS) { |
66 | if (event_ctx->event == |
67 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
68 | /* 1A-08: consider ake timeout a failure */ |
69 | /* some hdmi receivers are not ready for HDCP |
70 | * immediately after video becomes active, |
71 | * delay 1s before retry on first HDCP message |
72 | * timeout. |
73 | */ |
74 | fail_and_restart_in_ms(time: 1000, status: &status, output); |
75 | } else { |
76 | /* continue ake cert polling*/ |
77 | callback_in_ms(time: 10, output); |
78 | increment_stay_counter(hdcp); |
79 | } |
80 | break; |
81 | } else if (input->ake_cert_read != PASS || |
82 | input->ake_cert_validation != PASS) { |
83 | /* |
84 | * 1A-09: consider invalid ake cert a failure |
85 | * 1A-10: consider receiver id listed in SRM a failure |
86 | */ |
87 | fail_and_restart_in_ms(time: 0, status: &status, output); |
88 | break; |
89 | } |
90 | if (conn->is_km_stored && |
91 | !adjust->hdcp2.force_no_stored_km) { |
92 | callback_in_ms(time: 0, output); |
93 | set_state_id(hdcp, output, id: H2_A1_SEND_STORED_KM); |
94 | } else { |
95 | callback_in_ms(time: 0, output); |
96 | set_state_id(hdcp, output, id: H2_A1_SEND_NO_STORED_KM); |
97 | } |
98 | break; |
99 | case H2_A1_SEND_NO_STORED_KM: |
100 | if (input->no_stored_km_write != PASS) { |
101 | fail_and_restart_in_ms(time: 0, status: &status, output); |
102 | break; |
103 | } |
104 | if (adjust->hdcp2.increase_h_prime_timeout) |
105 | set_watchdog_in_ms(hdcp, time: 2000, output); |
106 | else |
107 | set_watchdog_in_ms(hdcp, time: 1000, output); |
108 | callback_in_ms(time: 0, output); |
109 | set_state_id(hdcp, output, id: H2_A1_READ_H_PRIME); |
110 | break; |
111 | case H2_A1_READ_H_PRIME: |
112 | if (input->h_prime_available != PASS) { |
113 | if (event_ctx->event == |
114 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
115 | /* 1A-11-3: consider h' timeout a failure */ |
116 | fail_and_restart_in_ms(time: 1000, status: &status, output); |
117 | } else { |
118 | /* continue h' polling */ |
119 | callback_in_ms(time: 100, output); |
120 | increment_stay_counter(hdcp); |
121 | } |
122 | break; |
123 | } else if (input->h_prime_read != PASS) { |
124 | fail_and_restart_in_ms(time: 0, status: &status, output); |
125 | break; |
126 | } |
127 | set_watchdog_in_ms(hdcp, time: 200, output); |
128 | callback_in_ms(time: 0, output); |
129 | set_state_id(hdcp, output, id: H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME); |
130 | break; |
131 | case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: |
132 | if (input->pairing_available != PASS) { |
133 | if (event_ctx->event == |
134 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
135 | /* 1A-12: consider pairing info timeout |
136 | * a failure |
137 | */ |
138 | fail_and_restart_in_ms(time: 0, status: &status, output); |
139 | } else { |
140 | /* continue pairing info polling */ |
141 | callback_in_ms(time: 20, output); |
142 | increment_stay_counter(hdcp); |
143 | } |
144 | break; |
145 | } else if (input->pairing_info_read != PASS || |
146 | input->h_prime_validation != PASS) { |
147 | /* 1A-11-1: consider invalid h' a failure */ |
148 | fail_and_restart_in_ms(time: 0, status: &status, output); |
149 | break; |
150 | } |
151 | callback_in_ms(time: 0, output); |
152 | set_state_id(hdcp, output, id: H2_A2_LOCALITY_CHECK); |
153 | break; |
154 | case H2_A1_SEND_STORED_KM: |
155 | if (input->stored_km_write != PASS) { |
156 | fail_and_restart_in_ms(time: 0, status: &status, output); |
157 | break; |
158 | } |
159 | set_watchdog_in_ms(hdcp, time: 200, output); |
160 | callback_in_ms(time: 0, output); |
161 | set_state_id(hdcp, output, id: H2_A1_VALIDATE_H_PRIME); |
162 | break; |
163 | case H2_A1_VALIDATE_H_PRIME: |
164 | if (input->h_prime_available != PASS) { |
165 | if (event_ctx->event == |
166 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
167 | /* 1A-11-2: consider h' timeout a failure */ |
168 | fail_and_restart_in_ms(time: 1000, status: &status, output); |
169 | } else { |
170 | /* continue h' polling */ |
171 | callback_in_ms(time: 20, output); |
172 | increment_stay_counter(hdcp); |
173 | } |
174 | break; |
175 | } else if (input->h_prime_read != PASS) { |
176 | fail_and_restart_in_ms(time: 0, status: &status, output); |
177 | break; |
178 | } else if (input->h_prime_validation != PASS) { |
179 | /* 1A-11-1: consider invalid h' a failure */ |
180 | adjust->hdcp2.force_no_stored_km = 1; |
181 | fail_and_restart_in_ms(time: 0, status: &status, output); |
182 | break; |
183 | } |
184 | callback_in_ms(time: 0, output); |
185 | set_state_id(hdcp, output, id: H2_A2_LOCALITY_CHECK); |
186 | break; |
187 | case H2_A2_LOCALITY_CHECK: |
188 | if (hdcp->state.stay_count > 10 || |
189 | input->lc_init_prepare != PASS || |
190 | input->lc_init_write != PASS || |
191 | input->l_prime_available_poll != PASS || |
192 | input->l_prime_read != PASS) { |
193 | /* |
194 | * 1A-05: consider disconnection after LC init a failure |
195 | * 1A-13-1: consider invalid l' a failure |
196 | * 1A-13-2: consider l' timeout a failure |
197 | */ |
198 | fail_and_restart_in_ms(time: 0, status: &status, output); |
199 | break; |
200 | } else if (input->l_prime_validation != PASS) { |
201 | callback_in_ms(time: 0, output); |
202 | increment_stay_counter(hdcp); |
203 | break; |
204 | } |
205 | callback_in_ms(time: 0, output); |
206 | set_state_id(hdcp, output, id: H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER); |
207 | break; |
208 | case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER: |
209 | if (input->eks_prepare != PASS || |
210 | input->eks_write != PASS) { |
211 | fail_and_restart_in_ms(time: 0, status: &status, output); |
212 | break; |
213 | } |
214 | if (conn->is_repeater) { |
215 | set_watchdog_in_ms(hdcp, time: 3000, output); |
216 | callback_in_ms(time: 0, output); |
217 | set_state_id(hdcp, output, id: H2_A6_WAIT_FOR_RX_ID_LIST); |
218 | } else { |
219 | /* some CTS equipment requires a delay GREATER than |
220 | * 200 ms, so delay 210 ms instead of 200 ms |
221 | */ |
222 | callback_in_ms(time: 210, output); |
223 | set_state_id(hdcp, output, id: H2_ENABLE_ENCRYPTION); |
224 | } |
225 | break; |
226 | case H2_ENABLE_ENCRYPTION: |
227 | if (input->rxstatus_read != PASS || |
228 | input->reauth_request_check != PASS) { |
229 | /* |
230 | * 1A-07: restart hdcp on REAUTH_REQ |
231 | * 1B-08: restart hdcp on REAUTH_REQ |
232 | */ |
233 | fail_and_restart_in_ms(time: 0, status: &status, output); |
234 | break; |
235 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
236 | callback_in_ms(time: 0, output); |
237 | set_state_id(hdcp, output, id: H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
238 | break; |
239 | } else if (input->enable_encryption != PASS) { |
240 | fail_and_restart_in_ms(time: 0, status: &status, output); |
241 | break; |
242 | } |
243 | callback_in_ms(time: 0, output); |
244 | set_state_id(hdcp, output, id: H2_A5_AUTHENTICATED); |
245 | set_auth_complete(hdcp, output); |
246 | break; |
247 | case H2_A5_AUTHENTICATED: |
248 | if (input->rxstatus_read == FAIL || |
249 | input->reauth_request_check == FAIL) { |
250 | fail_and_restart_in_ms(time: 0, status: &status, output); |
251 | break; |
252 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
253 | callback_in_ms(time: 0, output); |
254 | set_state_id(hdcp, output, id: H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
255 | break; |
256 | } |
257 | callback_in_ms(time: 500, output); |
258 | increment_stay_counter(hdcp); |
259 | break; |
260 | case H2_A6_WAIT_FOR_RX_ID_LIST: |
261 | if (input->rxstatus_read != PASS || |
262 | input->reauth_request_check != PASS) { |
263 | fail_and_restart_in_ms(time: 0, status: &status, output); |
264 | break; |
265 | } else if (!event_ctx->rx_id_list_ready) { |
266 | if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
267 | /* 1B-02: consider rx id list timeout a failure */ |
268 | /* some CTS equipment's actual timeout |
269 | * measurement is slightly greater than 3000 ms. |
270 | * Delay 100 ms to ensure it is fully timeout |
271 | * before re-authentication. |
272 | */ |
273 | fail_and_restart_in_ms(time: 100, status: &status, output); |
274 | } else { |
275 | callback_in_ms(time: 300, output); |
276 | increment_stay_counter(hdcp); |
277 | } |
278 | break; |
279 | } |
280 | callback_in_ms(time: 0, output); |
281 | set_state_id(hdcp, output, id: H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
282 | break; |
283 | case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: |
284 | if (input->rxstatus_read != PASS || |
285 | input->reauth_request_check != PASS || |
286 | input->rx_id_list_read != PASS || |
287 | input->device_count_check != PASS || |
288 | input->rx_id_list_validation != PASS || |
289 | input->repeater_auth_ack_write != PASS) { |
290 | /* 1B-03: consider invalid v' a failure |
291 | * 1B-04: consider MAX_DEVS_EXCEEDED a failure |
292 | * 1B-05: consider MAX_CASCADE_EXCEEDED a failure |
293 | * 1B-06: consider invalid seq_num_V a failure |
294 | * 1B-09: consider seq_num_V rollover a failure |
295 | */ |
296 | fail_and_restart_in_ms(time: 0, status: &status, output); |
297 | break; |
298 | } |
299 | callback_in_ms(time: 0, output); |
300 | set_state_id(hdcp, output, id: H2_A9_SEND_STREAM_MANAGEMENT); |
301 | break; |
302 | case H2_A9_SEND_STREAM_MANAGEMENT: |
303 | if (input->rxstatus_read != PASS || |
304 | input->reauth_request_check != PASS) { |
305 | fail_and_restart_in_ms(time: 0, status: &status, output); |
306 | break; |
307 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
308 | callback_in_ms(time: 0, output); |
309 | set_state_id(hdcp, output, id: H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
310 | break; |
311 | } else if (input->prepare_stream_manage != PASS || |
312 | input->stream_manage_write != PASS) { |
313 | fail_and_restart_in_ms(time: 0, status: &status, output); |
314 | break; |
315 | } |
316 | set_watchdog_in_ms(hdcp, time: 100, output); |
317 | callback_in_ms(time: 0, output); |
318 | set_state_id(hdcp, output, id: H2_A9_VALIDATE_STREAM_READY); |
319 | break; |
320 | case H2_A9_VALIDATE_STREAM_READY: |
321 | if (input->rxstatus_read != PASS || |
322 | input->reauth_request_check != PASS) { |
323 | fail_and_restart_in_ms(time: 0, status: &status, output); |
324 | break; |
325 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
326 | callback_in_ms(time: 0, output); |
327 | set_state_id(hdcp, output, id: H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
328 | break; |
329 | } else if (input->stream_ready_available != PASS) { |
330 | if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
331 | /* 1B-10-2: restart content stream management on |
332 | * stream ready timeout |
333 | */ |
334 | hdcp->auth.count.stream_management_retry_count++; |
335 | callback_in_ms(time: 0, output); |
336 | set_state_id(hdcp, output, id: H2_A9_SEND_STREAM_MANAGEMENT); |
337 | } else { |
338 | callback_in_ms(time: 10, output); |
339 | increment_stay_counter(hdcp); |
340 | } |
341 | break; |
342 | } else if (input->stream_ready_read != PASS || |
343 | input->stream_ready_validation != PASS) { |
344 | /* |
345 | * 1B-10-1: restart content stream management |
346 | * on invalid M' |
347 | */ |
348 | if (hdcp->auth.count.stream_management_retry_count > 10) { |
349 | fail_and_restart_in_ms(time: 0, status: &status, output); |
350 | } else { |
351 | hdcp->auth.count.stream_management_retry_count++; |
352 | callback_in_ms(time: 0, output); |
353 | set_state_id(hdcp, output, id: H2_A9_SEND_STREAM_MANAGEMENT); |
354 | } |
355 | break; |
356 | } |
357 | callback_in_ms(time: 200, output); |
358 | set_state_id(hdcp, output, id: H2_ENABLE_ENCRYPTION); |
359 | break; |
360 | default: |
361 | status = MOD_HDCP_STATUS_INVALID_STATE; |
362 | fail_and_restart_in_ms(time: 0, status: &status, output); |
363 | break; |
364 | } |
365 | |
366 | return status; |
367 | } |
368 | |
369 | enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp, |
370 | struct mod_hdcp_event_context *event_ctx, |
371 | struct mod_hdcp_transition_input_hdcp2 *input, |
372 | struct mod_hdcp_output *output) |
373 | { |
374 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
375 | struct mod_hdcp_connection *conn = &hdcp->connection; |
376 | struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust; |
377 | |
378 | switch (current_state(hdcp)) { |
379 | case D2_A0_DETERMINE_RX_HDCP_CAPABLE: |
380 | if (input->rx_caps_read_dp != PASS || |
381 | input->hdcp2_capable_check != PASS) { |
382 | adjust->hdcp2.disable = 1; |
383 | callback_in_ms(time: 0, output); |
384 | set_state_id(hdcp, output, id: HDCP_INITIALIZED); |
385 | } else { |
386 | callback_in_ms(time: 0, output); |
387 | set_state_id(hdcp, output, id: D2_A1_SEND_AKE_INIT); |
388 | } |
389 | break; |
390 | case D2_A1_SEND_AKE_INIT: |
391 | if (input->create_session != PASS || |
392 | input->ake_init_prepare != PASS) { |
393 | /* out of sync with psp state */ |
394 | adjust->hdcp2.disable = 1; |
395 | fail_and_restart_in_ms(time: 0, status: &status, output); |
396 | break; |
397 | } else if (input->ake_init_write != PASS) { |
398 | /* possibly display not ready */ |
399 | fail_and_restart_in_ms(time: 0, status: &status, output); |
400 | break; |
401 | } |
402 | callback_in_ms(time: 100, output); |
403 | set_state_id(hdcp, output, id: D2_A1_VALIDATE_AKE_CERT); |
404 | break; |
405 | case D2_A1_VALIDATE_AKE_CERT: |
406 | if (input->ake_cert_read != PASS || |
407 | input->ake_cert_validation != PASS) { |
408 | /* |
409 | * 1A-08: consider invalid ake cert a failure |
410 | * 1A-09: consider receiver id listed in SRM a failure |
411 | */ |
412 | fail_and_restart_in_ms(time: 0, status: &status, output); |
413 | break; |
414 | } |
415 | if (conn->is_km_stored && |
416 | !adjust->hdcp2.force_no_stored_km) { |
417 | callback_in_ms(time: 0, output); |
418 | set_state_id(hdcp, output, id: D2_A1_SEND_STORED_KM); |
419 | } else { |
420 | callback_in_ms(time: 0, output); |
421 | set_state_id(hdcp, output, id: D2_A1_SEND_NO_STORED_KM); |
422 | } |
423 | break; |
424 | case D2_A1_SEND_NO_STORED_KM: |
425 | if (input->no_stored_km_write != PASS) { |
426 | fail_and_restart_in_ms(time: 0, status: &status, output); |
427 | break; |
428 | } |
429 | if (adjust->hdcp2.increase_h_prime_timeout) |
430 | set_watchdog_in_ms(hdcp, time: 2000, output); |
431 | else |
432 | set_watchdog_in_ms(hdcp, time: 1000, output); |
433 | set_state_id(hdcp, output, id: D2_A1_READ_H_PRIME); |
434 | break; |
435 | case D2_A1_READ_H_PRIME: |
436 | if (input->h_prime_available != PASS) { |
437 | if (event_ctx->event == |
438 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) |
439 | /* 1A-10-3: consider h' timeout a failure */ |
440 | fail_and_restart_in_ms(time: 1000, status: &status, output); |
441 | else |
442 | increment_stay_counter(hdcp); |
443 | break; |
444 | } else if (input->h_prime_read != PASS) { |
445 | fail_and_restart_in_ms(time: 0, status: &status, output); |
446 | break; |
447 | } |
448 | set_watchdog_in_ms(hdcp, time: 200, output); |
449 | set_state_id(hdcp, output, id: D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME); |
450 | break; |
451 | case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: |
452 | if (input->pairing_available != PASS) { |
453 | if (event_ctx->event == |
454 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) |
455 | /* |
456 | * 1A-11: consider pairing info timeout |
457 | * a failure |
458 | */ |
459 | fail_and_restart_in_ms(time: 0, status: &status, output); |
460 | else |
461 | increment_stay_counter(hdcp); |
462 | break; |
463 | } else if (input->pairing_info_read != PASS || |
464 | input->h_prime_validation != PASS) { |
465 | /* 1A-10-1: consider invalid h' a failure */ |
466 | fail_and_restart_in_ms(time: 0, status: &status, output); |
467 | break; |
468 | } |
469 | callback_in_ms(time: 0, output); |
470 | set_state_id(hdcp, output, id: D2_A2_LOCALITY_CHECK); |
471 | break; |
472 | case D2_A1_SEND_STORED_KM: |
473 | if (input->stored_km_write != PASS) { |
474 | fail_and_restart_in_ms(time: 0, status: &status, output); |
475 | break; |
476 | } |
477 | set_watchdog_in_ms(hdcp, time: 200, output); |
478 | set_state_id(hdcp, output, id: D2_A1_VALIDATE_H_PRIME); |
479 | break; |
480 | case D2_A1_VALIDATE_H_PRIME: |
481 | if (input->h_prime_available != PASS) { |
482 | if (event_ctx->event == |
483 | MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) |
484 | /* 1A-10-2: consider h' timeout a failure */ |
485 | fail_and_restart_in_ms(time: 1000, status: &status, output); |
486 | else |
487 | increment_stay_counter(hdcp); |
488 | break; |
489 | } else if (input->h_prime_read != PASS) { |
490 | fail_and_restart_in_ms(time: 0, status: &status, output); |
491 | break; |
492 | } else if (input->h_prime_validation != PASS) { |
493 | /* 1A-10-1: consider invalid h' a failure */ |
494 | adjust->hdcp2.force_no_stored_km = 1; |
495 | fail_and_restart_in_ms(time: 0, status: &status, output); |
496 | break; |
497 | } |
498 | callback_in_ms(time: 0, output); |
499 | set_state_id(hdcp, output, id: D2_A2_LOCALITY_CHECK); |
500 | break; |
501 | case D2_A2_LOCALITY_CHECK: |
502 | if (hdcp->state.stay_count > 10 || |
503 | input->lc_init_prepare != PASS || |
504 | input->lc_init_write != PASS || |
505 | input->l_prime_read != PASS) { |
506 | /* 1A-12: consider invalid l' a failure */ |
507 | fail_and_restart_in_ms(time: 0, status: &status, output); |
508 | break; |
509 | } else if (input->l_prime_validation != PASS) { |
510 | callback_in_ms(time: 0, output); |
511 | increment_stay_counter(hdcp); |
512 | break; |
513 | } |
514 | callback_in_ms(time: 0, output); |
515 | set_state_id(hdcp, output, id: D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER); |
516 | break; |
517 | case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER: |
518 | if (input->eks_prepare != PASS || |
519 | input->eks_write != PASS) { |
520 | fail_and_restart_in_ms(time: 0, status: &status, output); |
521 | break; |
522 | } |
523 | if (conn->is_repeater) { |
524 | set_watchdog_in_ms(hdcp, time: 3000, output); |
525 | set_state_id(hdcp, output, id: D2_A6_WAIT_FOR_RX_ID_LIST); |
526 | } else { |
527 | callback_in_ms(time: 1, output); |
528 | set_state_id(hdcp, output, id: D2_SEND_CONTENT_STREAM_TYPE); |
529 | } |
530 | break; |
531 | case D2_SEND_CONTENT_STREAM_TYPE: |
532 | if (input->rxstatus_read != PASS || |
533 | input->reauth_request_check != PASS || |
534 | input->link_integrity_check_dp != PASS || |
535 | input->content_stream_type_write != PASS) { |
536 | fail_and_restart_in_ms(time: 0, status: &status, output); |
537 | break; |
538 | } |
539 | callback_in_ms(time: 210, output); |
540 | set_state_id(hdcp, output, id: D2_ENABLE_ENCRYPTION); |
541 | break; |
542 | case D2_ENABLE_ENCRYPTION: |
543 | if (input->rxstatus_read != PASS || |
544 | input->reauth_request_check != PASS || |
545 | input->link_integrity_check_dp != PASS) { |
546 | /* |
547 | * 1A-07: restart hdcp on REAUTH_REQ |
548 | * 1B-08: restart hdcp on REAUTH_REQ |
549 | */ |
550 | fail_and_restart_in_ms(time: 0, status: &status, output); |
551 | break; |
552 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
553 | callback_in_ms(time: 0, output); |
554 | set_state_id(hdcp, output, id: D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
555 | break; |
556 | } else if (input->enable_encryption != PASS || |
557 | (is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) { |
558 | fail_and_restart_in_ms(time: 0, status: &status, output); |
559 | break; |
560 | } |
561 | set_state_id(hdcp, output, id: D2_A5_AUTHENTICATED); |
562 | set_auth_complete(hdcp, output); |
563 | break; |
564 | case D2_A5_AUTHENTICATED: |
565 | if (input->rxstatus_read == FAIL || |
566 | input->reauth_request_check == FAIL) { |
567 | fail_and_restart_in_ms(time: 100, status: &status, output); |
568 | break; |
569 | } else if (input->link_integrity_check_dp == FAIL) { |
570 | if (hdcp->connection.hdcp2_retry_count >= 1) |
571 | adjust->hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; |
572 | fail_and_restart_in_ms(time: 0, status: &status, output); |
573 | break; |
574 | } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { |
575 | callback_in_ms(time: 0, output); |
576 | set_state_id(hdcp, output, id: D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
577 | break; |
578 | } |
579 | increment_stay_counter(hdcp); |
580 | break; |
581 | case D2_A6_WAIT_FOR_RX_ID_LIST: |
582 | if (input->rxstatus_read != PASS || |
583 | input->reauth_request_check != PASS || |
584 | input->link_integrity_check_dp != PASS) { |
585 | fail_and_restart_in_ms(time: 0, status: &status, output); |
586 | break; |
587 | } else if (!event_ctx->rx_id_list_ready) { |
588 | if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) |
589 | /* 1B-02: consider rx id list timeout a failure */ |
590 | fail_and_restart_in_ms(time: 0, status: &status, output); |
591 | else |
592 | increment_stay_counter(hdcp); |
593 | break; |
594 | } |
595 | callback_in_ms(time: 0, output); |
596 | set_state_id(hdcp, output, id: D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
597 | break; |
598 | case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: |
599 | if (input->rxstatus_read != PASS || |
600 | input->reauth_request_check != PASS || |
601 | input->link_integrity_check_dp != PASS || |
602 | input->rx_id_list_read != PASS || |
603 | input->device_count_check != PASS || |
604 | input->rx_id_list_validation != PASS || |
605 | input->repeater_auth_ack_write != PASS) { |
606 | /* |
607 | * 1B-03: consider invalid v' a failure |
608 | * 1B-04: consider MAX_DEVS_EXCEEDED a failure |
609 | * 1B-05: consider MAX_CASCADE_EXCEEDED a failure |
610 | * 1B-06: consider invalid seq_num_V a failure |
611 | * 1B-09: consider seq_num_V rollover a failure |
612 | */ |
613 | fail_and_restart_in_ms(time: 0, status: &status, output); |
614 | break; |
615 | } |
616 | callback_in_ms(time: 0, output); |
617 | set_state_id(hdcp, output, id: D2_A9_SEND_STREAM_MANAGEMENT); |
618 | break; |
619 | case D2_A9_SEND_STREAM_MANAGEMENT: |
620 | if (input->rxstatus_read != PASS || |
621 | input->reauth_request_check != PASS || |
622 | input->link_integrity_check_dp != PASS) { |
623 | fail_and_restart_in_ms(time: 0, status: &status, output); |
624 | break; |
625 | } else if (event_ctx->rx_id_list_ready) { |
626 | callback_in_ms(time: 0, output); |
627 | set_state_id(hdcp, output, id: D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
628 | break; |
629 | } else if (input->prepare_stream_manage != PASS || |
630 | input->stream_manage_write != PASS) { |
631 | if (event_ctx->event == MOD_HDCP_EVENT_CALLBACK) |
632 | fail_and_restart_in_ms(time: 0, status: &status, output); |
633 | else |
634 | increment_stay_counter(hdcp); |
635 | break; |
636 | } |
637 | callback_in_ms(time: 100, output); |
638 | set_state_id(hdcp, output, id: D2_A9_VALIDATE_STREAM_READY); |
639 | break; |
640 | case D2_A9_VALIDATE_STREAM_READY: |
641 | if (input->rxstatus_read != PASS || |
642 | input->reauth_request_check != PASS || |
643 | input->link_integrity_check_dp != PASS) { |
644 | fail_and_restart_in_ms(time: 0, status: &status, output); |
645 | break; |
646 | } else if (event_ctx->rx_id_list_ready) { |
647 | callback_in_ms(time: 0, output); |
648 | set_state_id(hdcp, output, id: D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); |
649 | break; |
650 | } else if (input->stream_ready_read != PASS || |
651 | input->stream_ready_validation != PASS) { |
652 | /* |
653 | * 1B-10-1: restart content stream management |
654 | * on invalid M' |
655 | * 1B-10-2: consider stream ready timeout a failure |
656 | */ |
657 | if (hdcp->auth.count.stream_management_retry_count > 10) { |
658 | fail_and_restart_in_ms(time: 0, status: &status, output); |
659 | } else if (event_ctx->event == MOD_HDCP_EVENT_CALLBACK) { |
660 | hdcp->auth.count.stream_management_retry_count++; |
661 | callback_in_ms(time: 0, output); |
662 | set_state_id(hdcp, output, id: D2_A9_SEND_STREAM_MANAGEMENT); |
663 | } else { |
664 | increment_stay_counter(hdcp); |
665 | } |
666 | break; |
667 | } |
668 | callback_in_ms(time: 200, output); |
669 | set_state_id(hdcp, output, id: D2_ENABLE_ENCRYPTION); |
670 | break; |
671 | default: |
672 | status = MOD_HDCP_STATUS_INVALID_STATE; |
673 | fail_and_restart_in_ms(time: 0, status: &status, output); |
674 | break; |
675 | } |
676 | return status; |
677 | } |
678 | |