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 <linux/delay.h> |
27 | |
28 | #include "hdcp.h" |
29 | |
30 | static inline enum mod_hdcp_status check_receiver_id_list_ready(struct mod_hdcp *hdcp) |
31 | { |
32 | uint8_t is_ready = 0; |
33 | |
34 | if (is_dp_hdcp(hdcp)) |
35 | is_ready = HDCP_2_2_DP_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus_dp) ? 1 : 0; |
36 | else |
37 | is_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus[1]) && |
38 | (HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
39 | hdcp->auth.msg.hdcp2.rxstatus[0])) ? 1 : 0; |
40 | return is_ready ? MOD_HDCP_STATUS_SUCCESS : |
41 | MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY; |
42 | } |
43 | |
44 | static inline enum mod_hdcp_status check_hdcp2_capable(struct mod_hdcp *hdcp) |
45 | { |
46 | enum mod_hdcp_status status; |
47 | |
48 | if (is_dp_hdcp(hdcp)) |
49 | status = (hdcp->auth.msg.hdcp2.rxcaps_dp[0] == HDCP_2_2_RX_CAPS_VERSION_VAL) && |
50 | HDCP_2_2_DP_HDCP_CAPABLE(hdcp->auth.msg.hdcp2.rxcaps_dp[2]) ? |
51 | MOD_HDCP_STATUS_SUCCESS : |
52 | MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE; |
53 | else |
54 | status = (hdcp->auth.msg.hdcp2.hdcp2version_hdmi & HDCP_2_2_HDMI_SUPPORT_MASK) ? |
55 | MOD_HDCP_STATUS_SUCCESS : |
56 | MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE; |
57 | return status; |
58 | } |
59 | |
60 | static inline enum mod_hdcp_status check_reauthentication_request( |
61 | struct mod_hdcp *hdcp) |
62 | { |
63 | uint8_t ret = 0; |
64 | |
65 | if (is_dp_hdcp(hdcp)) |
66 | ret = HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(hdcp->auth.msg.hdcp2.rxstatus_dp) ? |
67 | MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST : |
68 | MOD_HDCP_STATUS_SUCCESS; |
69 | else |
70 | ret = HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(hdcp->auth.msg.hdcp2.rxstatus[1]) ? |
71 | MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST : |
72 | MOD_HDCP_STATUS_SUCCESS; |
73 | return ret; |
74 | } |
75 | |
76 | static inline enum mod_hdcp_status check_link_integrity_failure_dp( |
77 | struct mod_hdcp *hdcp) |
78 | { |
79 | return HDCP_2_2_DP_RXSTATUS_LINK_FAILED(hdcp->auth.msg.hdcp2.rxstatus_dp) ? |
80 | MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE : |
81 | MOD_HDCP_STATUS_SUCCESS; |
82 | } |
83 | |
84 | static enum mod_hdcp_status check_ake_cert_available(struct mod_hdcp *hdcp) |
85 | { |
86 | enum mod_hdcp_status status; |
87 | uint16_t size; |
88 | |
89 | if (is_dp_hdcp(hdcp)) { |
90 | status = MOD_HDCP_STATUS_SUCCESS; |
91 | } else { |
92 | status = mod_hdcp_read_rxstatus(hdcp); |
93 | if (status == MOD_HDCP_STATUS_SUCCESS) { |
94 | size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
95 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
96 | status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_cert)) ? |
97 | MOD_HDCP_STATUS_SUCCESS : |
98 | MOD_HDCP_STATUS_HDCP2_AKE_CERT_PENDING; |
99 | } |
100 | } |
101 | return status; |
102 | } |
103 | |
104 | static enum mod_hdcp_status check_h_prime_available(struct mod_hdcp *hdcp) |
105 | { |
106 | enum mod_hdcp_status status; |
107 | uint8_t size; |
108 | |
109 | status = mod_hdcp_read_rxstatus(hdcp); |
110 | if (status != MOD_HDCP_STATUS_SUCCESS) |
111 | goto out; |
112 | |
113 | if (is_dp_hdcp(hdcp)) { |
114 | status = HDCP_2_2_DP_RXSTATUS_H_PRIME(hdcp->auth.msg.hdcp2.rxstatus_dp) ? |
115 | MOD_HDCP_STATUS_SUCCESS : |
116 | MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; |
117 | } else { |
118 | size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
119 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
120 | status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)) ? |
121 | MOD_HDCP_STATUS_SUCCESS : |
122 | MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; |
123 | } |
124 | out: |
125 | return status; |
126 | } |
127 | |
128 | static enum mod_hdcp_status check_pairing_info_available(struct mod_hdcp *hdcp) |
129 | { |
130 | enum mod_hdcp_status status; |
131 | uint8_t size; |
132 | |
133 | status = mod_hdcp_read_rxstatus(hdcp); |
134 | if (status != MOD_HDCP_STATUS_SUCCESS) |
135 | goto out; |
136 | |
137 | if (is_dp_hdcp(hdcp)) { |
138 | status = HDCP_2_2_DP_RXSTATUS_PAIRING(hdcp->auth.msg.hdcp2.rxstatus_dp) ? |
139 | MOD_HDCP_STATUS_SUCCESS : |
140 | MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; |
141 | } else { |
142 | size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
143 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
144 | status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)) ? |
145 | MOD_HDCP_STATUS_SUCCESS : |
146 | MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; |
147 | } |
148 | out: |
149 | return status; |
150 | } |
151 | |
152 | static enum mod_hdcp_status poll_l_prime_available(struct mod_hdcp *hdcp) |
153 | { |
154 | enum mod_hdcp_status status; |
155 | uint8_t size; |
156 | uint16_t max_wait = 20; // units of ms |
157 | uint16_t num_polls = 5; |
158 | uint16_t wait_time = max_wait / num_polls; |
159 | |
160 | if (is_dp_hdcp(hdcp)) |
161 | status = MOD_HDCP_STATUS_INVALID_OPERATION; |
162 | else |
163 | for (; num_polls; num_polls--) { |
164 | msleep(msecs: wait_time); |
165 | |
166 | status = mod_hdcp_read_rxstatus(hdcp); |
167 | if (status != MOD_HDCP_STATUS_SUCCESS) |
168 | break; |
169 | |
170 | size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
171 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
172 | status = (size == sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)) ? |
173 | MOD_HDCP_STATUS_SUCCESS : |
174 | MOD_HDCP_STATUS_HDCP2_L_PRIME_PENDING; |
175 | if (status == MOD_HDCP_STATUS_SUCCESS) |
176 | break; |
177 | } |
178 | return status; |
179 | } |
180 | |
181 | static enum mod_hdcp_status check_stream_ready_available(struct mod_hdcp *hdcp) |
182 | { |
183 | enum mod_hdcp_status status; |
184 | uint8_t size; |
185 | |
186 | if (is_dp_hdcp(hdcp)) { |
187 | status = MOD_HDCP_STATUS_INVALID_OPERATION; |
188 | } else { |
189 | status = mod_hdcp_read_rxstatus(hdcp); |
190 | if (status != MOD_HDCP_STATUS_SUCCESS) |
191 | goto out; |
192 | size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
193 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
194 | status = (size == sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)) ? |
195 | MOD_HDCP_STATUS_SUCCESS : |
196 | MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING; |
197 | } |
198 | out: |
199 | return status; |
200 | } |
201 | |
202 | static inline uint8_t get_device_count(struct mod_hdcp *hdcp) |
203 | { |
204 | return HDCP_2_2_DEV_COUNT_LO(hdcp->auth.msg.hdcp2.rx_id_list[2]) + |
205 | (HDCP_2_2_DEV_COUNT_HI(hdcp->auth.msg.hdcp2.rx_id_list[1]) << 4); |
206 | } |
207 | |
208 | static enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) |
209 | { |
210 | /* Avoid device count == 0 to do authentication */ |
211 | if (get_device_count(hdcp) == 0) |
212 | return MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE; |
213 | |
214 | /* Some MST display may choose to report the internal panel as an HDCP RX. */ |
215 | /* To update this condition with 1(because the immediate repeater's internal */ |
216 | /* panel is possibly not included in DEVICE_COUNT) + get_device_count(hdcp). */ |
217 | /* Device count must be greater than or equal to tracked hdcp displays. */ |
218 | return ((1 + get_device_count(hdcp)) < get_active_display_count(hdcp)) ? |
219 | MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE : |
220 | MOD_HDCP_STATUS_SUCCESS; |
221 | } |
222 | |
223 | static uint8_t process_rxstatus(struct mod_hdcp *hdcp, |
224 | struct mod_hdcp_event_context *event_ctx, |
225 | struct mod_hdcp_transition_input_hdcp2 *input, |
226 | enum mod_hdcp_status *status) |
227 | { |
228 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_rxstatus, |
229 | flag: &input->rxstatus_read, status, |
230 | hdcp, str: "rxstatus_read" )) |
231 | goto out; |
232 | if (!mod_hdcp_execute_and_set(func: check_reauthentication_request, |
233 | flag: &input->reauth_request_check, status, |
234 | hdcp, str: "reauth_request_check" )) |
235 | goto out; |
236 | if (is_dp_hdcp(hdcp)) { |
237 | if (!mod_hdcp_execute_and_set(func: check_link_integrity_failure_dp, |
238 | flag: &input->link_integrity_check_dp, status, |
239 | hdcp, str: "link_integrity_check_dp" )) |
240 | goto out; |
241 | } |
242 | if (hdcp->connection.is_repeater) |
243 | if (check_receiver_id_list_ready(hdcp) == |
244 | MOD_HDCP_STATUS_SUCCESS) { |
245 | HDCP_INPUT_PASS_TRACE(hdcp, "rx_id_list_ready" ); |
246 | event_ctx->rx_id_list_ready = 1; |
247 | if (is_dp_hdcp(hdcp)) |
248 | hdcp->auth.msg.hdcp2.rx_id_list_size = |
249 | sizeof(hdcp->auth.msg.hdcp2.rx_id_list); |
250 | else |
251 | hdcp->auth.msg.hdcp2.rx_id_list_size = |
252 | HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | |
253 | hdcp->auth.msg.hdcp2.rxstatus[0]; |
254 | } |
255 | out: |
256 | return (*status == MOD_HDCP_STATUS_SUCCESS); |
257 | } |
258 | |
259 | static enum mod_hdcp_status known_hdcp2_capable_rx(struct mod_hdcp *hdcp, |
260 | struct mod_hdcp_event_context *event_ctx, |
261 | struct mod_hdcp_transition_input_hdcp2 *input) |
262 | { |
263 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
264 | |
265 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
266 | event_ctx->unexpected_event = 1; |
267 | goto out; |
268 | } |
269 | |
270 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_hdcp2version, |
271 | flag: &input->hdcp2version_read, status: &status, |
272 | hdcp, str: "hdcp2version_read" )) |
273 | goto out; |
274 | if (!mod_hdcp_execute_and_set(func: check_hdcp2_capable, |
275 | flag: &input->hdcp2_capable_check, status: &status, |
276 | hdcp, str: "hdcp2_capable" )) |
277 | goto out; |
278 | out: |
279 | return status; |
280 | } |
281 | |
282 | static enum mod_hdcp_status send_ake_init(struct mod_hdcp *hdcp, |
283 | struct mod_hdcp_event_context *event_ctx, |
284 | struct mod_hdcp_transition_input_hdcp2 *input) |
285 | { |
286 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
287 | |
288 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
289 | event_ctx->unexpected_event = 1; |
290 | goto out; |
291 | } |
292 | |
293 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_create_session, |
294 | flag: &input->create_session, status: &status, |
295 | hdcp, str: "create_session" )) |
296 | goto out; |
297 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_prepare_ake_init, |
298 | flag: &input->ake_init_prepare, status: &status, |
299 | hdcp, str: "ake_init_prepare" )) |
300 | goto out; |
301 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_ake_init, |
302 | flag: &input->ake_init_write, status: &status, |
303 | hdcp, str: "ake_init_write" )) |
304 | goto out; |
305 | out: |
306 | return status; |
307 | } |
308 | |
309 | static enum mod_hdcp_status validate_ake_cert(struct mod_hdcp *hdcp, |
310 | struct mod_hdcp_event_context *event_ctx, |
311 | struct mod_hdcp_transition_input_hdcp2 *input) |
312 | { |
313 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
314 | |
315 | |
316 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
317 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
318 | event_ctx->unexpected_event = 1; |
319 | goto out; |
320 | } |
321 | |
322 | if (is_hdmi_dvi_sl_hdcp(hdcp)) |
323 | if (!mod_hdcp_execute_and_set(func: check_ake_cert_available, |
324 | flag: &input->ake_cert_available, status: &status, |
325 | hdcp, str: "ake_cert_available" )) |
326 | goto out; |
327 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_ake_cert, |
328 | flag: &input->ake_cert_read, status: &status, |
329 | hdcp, str: "ake_cert_read" )) |
330 | goto out; |
331 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_ake_cert, |
332 | flag: &input->ake_cert_validation, status: &status, |
333 | hdcp, str: "ake_cert_validation" )) |
334 | goto out; |
335 | out: |
336 | return status; |
337 | } |
338 | |
339 | static enum mod_hdcp_status send_no_stored_km(struct mod_hdcp *hdcp, |
340 | struct mod_hdcp_event_context *event_ctx, |
341 | struct mod_hdcp_transition_input_hdcp2 *input) |
342 | { |
343 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
344 | |
345 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
346 | event_ctx->unexpected_event = 1; |
347 | goto out; |
348 | } |
349 | |
350 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_no_stored_km, |
351 | flag: &input->no_stored_km_write, status: &status, |
352 | hdcp, str: "no_stored_km_write" )) |
353 | goto out; |
354 | out: |
355 | return status; |
356 | } |
357 | |
358 | static enum mod_hdcp_status read_h_prime(struct mod_hdcp *hdcp, |
359 | struct mod_hdcp_event_context *event_ctx, |
360 | struct mod_hdcp_transition_input_hdcp2 *input) |
361 | { |
362 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
363 | |
364 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
365 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ && |
366 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
367 | event_ctx->unexpected_event = 1; |
368 | goto out; |
369 | } |
370 | |
371 | if (!mod_hdcp_execute_and_set(func: check_h_prime_available, |
372 | flag: &input->h_prime_available, status: &status, |
373 | hdcp, str: "h_prime_available" )) |
374 | goto out; |
375 | |
376 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_h_prime, |
377 | flag: &input->h_prime_read, status: &status, |
378 | hdcp, str: "h_prime_read" )) |
379 | goto out; |
380 | out: |
381 | return status; |
382 | } |
383 | |
384 | static enum mod_hdcp_status read_pairing_info_and_validate_h_prime( |
385 | struct mod_hdcp *hdcp, |
386 | struct mod_hdcp_event_context *event_ctx, |
387 | struct mod_hdcp_transition_input_hdcp2 *input) |
388 | { |
389 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
390 | |
391 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
392 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ && |
393 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
394 | event_ctx->unexpected_event = 1; |
395 | goto out; |
396 | } |
397 | |
398 | if (!mod_hdcp_execute_and_set(func: check_pairing_info_available, |
399 | flag: &input->pairing_available, status: &status, |
400 | hdcp, str: "pairing_available" )) |
401 | goto out; |
402 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_pairing_info, |
403 | flag: &input->pairing_info_read, status: &status, |
404 | hdcp, str: "pairing_info_read" )) |
405 | goto out; |
406 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_h_prime, |
407 | flag: &input->h_prime_validation, status: &status, |
408 | hdcp, str: "h_prime_validation" )) |
409 | goto out; |
410 | out: |
411 | return status; |
412 | } |
413 | |
414 | static enum mod_hdcp_status send_stored_km(struct mod_hdcp *hdcp, |
415 | struct mod_hdcp_event_context *event_ctx, |
416 | struct mod_hdcp_transition_input_hdcp2 *input) |
417 | { |
418 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
419 | |
420 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
421 | event_ctx->unexpected_event = 1; |
422 | goto out; |
423 | } |
424 | |
425 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_stored_km, |
426 | flag: &input->stored_km_write, status: &status, |
427 | hdcp, str: "stored_km_write" )) |
428 | goto out; |
429 | out: |
430 | return status; |
431 | } |
432 | |
433 | static enum mod_hdcp_status validate_h_prime(struct mod_hdcp *hdcp, |
434 | struct mod_hdcp_event_context *event_ctx, |
435 | struct mod_hdcp_transition_input_hdcp2 *input) |
436 | { |
437 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
438 | |
439 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
440 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ && |
441 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
442 | event_ctx->unexpected_event = 1; |
443 | goto out; |
444 | } |
445 | |
446 | if (!mod_hdcp_execute_and_set(func: check_h_prime_available, |
447 | flag: &input->h_prime_available, status: &status, |
448 | hdcp, str: "h_prime_available" )) |
449 | goto out; |
450 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_h_prime, |
451 | flag: &input->h_prime_read, status: &status, |
452 | hdcp, str: "h_prime_read" )) |
453 | goto out; |
454 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_h_prime, |
455 | flag: &input->h_prime_validation, status: &status, |
456 | hdcp, str: "h_prime_validation" )) |
457 | goto out; |
458 | out: |
459 | return status; |
460 | } |
461 | |
462 | static enum mod_hdcp_status locality_check(struct mod_hdcp *hdcp, |
463 | struct mod_hdcp_event_context *event_ctx, |
464 | struct mod_hdcp_transition_input_hdcp2 *input) |
465 | { |
466 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
467 | |
468 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
469 | event_ctx->unexpected_event = 1; |
470 | goto out; |
471 | } |
472 | |
473 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_prepare_lc_init, |
474 | flag: &input->lc_init_prepare, status: &status, |
475 | hdcp, str: "lc_init_prepare" )) |
476 | goto out; |
477 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_lc_init, |
478 | flag: &input->lc_init_write, status: &status, |
479 | hdcp, str: "lc_init_write" )) |
480 | goto out; |
481 | if (is_dp_hdcp(hdcp)) |
482 | msleep(msecs: 16); |
483 | else |
484 | if (!mod_hdcp_execute_and_set(func: poll_l_prime_available, |
485 | flag: &input->l_prime_available_poll, status: &status, |
486 | hdcp, str: "l_prime_available_poll" )) |
487 | goto out; |
488 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_l_prime, |
489 | flag: &input->l_prime_read, status: &status, |
490 | hdcp, str: "l_prime_read" )) |
491 | goto out; |
492 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_l_prime, |
493 | flag: &input->l_prime_validation, status: &status, |
494 | hdcp, str: "l_prime_validation" )) |
495 | goto out; |
496 | out: |
497 | return status; |
498 | } |
499 | |
500 | static enum mod_hdcp_status exchange_ks_and_test_for_repeater(struct mod_hdcp *hdcp, |
501 | struct mod_hdcp_event_context *event_ctx, |
502 | struct mod_hdcp_transition_input_hdcp2 *input) |
503 | { |
504 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
505 | |
506 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
507 | event_ctx->unexpected_event = 1; |
508 | goto out; |
509 | } |
510 | |
511 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_prepare_eks, |
512 | flag: &input->eks_prepare, status: &status, |
513 | hdcp, str: "eks_prepare" )) |
514 | goto out; |
515 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_eks, |
516 | flag: &input->eks_write, status: &status, |
517 | hdcp, str: "eks_write" )) |
518 | goto out; |
519 | out: |
520 | return status; |
521 | } |
522 | |
523 | static enum mod_hdcp_status enable_encryption(struct mod_hdcp *hdcp, |
524 | struct mod_hdcp_event_context *event_ctx, |
525 | struct mod_hdcp_transition_input_hdcp2 *input) |
526 | { |
527 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
528 | |
529 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
530 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { |
531 | event_ctx->unexpected_event = 1; |
532 | goto out; |
533 | } |
534 | if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { |
535 | process_rxstatus(hdcp, event_ctx, input, status: &status); |
536 | goto out; |
537 | } |
538 | |
539 | if (is_hdmi_dvi_sl_hdcp(hdcp)) { |
540 | if (!process_rxstatus(hdcp, event_ctx, input, status: &status)) |
541 | goto out; |
542 | if (event_ctx->rx_id_list_ready) |
543 | goto out; |
544 | } |
545 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_enable_encryption, |
546 | flag: &input->enable_encryption, status: &status, |
547 | hdcp, str: "enable_encryption" )) |
548 | goto out; |
549 | if (is_dp_mst_hdcp(hdcp)) { |
550 | if (!mod_hdcp_execute_and_set( |
551 | func: mod_hdcp_hdcp2_enable_dp_stream_encryption, |
552 | flag: &input->stream_encryption_dp, status: &status, |
553 | hdcp, str: "stream_encryption_dp" )) |
554 | goto out; |
555 | } |
556 | out: |
557 | return status; |
558 | } |
559 | |
560 | static enum mod_hdcp_status authenticated(struct mod_hdcp *hdcp, |
561 | struct mod_hdcp_event_context *event_ctx, |
562 | struct mod_hdcp_transition_input_hdcp2 *input) |
563 | { |
564 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
565 | |
566 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
567 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { |
568 | event_ctx->unexpected_event = 1; |
569 | goto out; |
570 | } |
571 | |
572 | process_rxstatus(hdcp, event_ctx, input, status: &status); |
573 | out: |
574 | return status; |
575 | } |
576 | |
577 | static enum mod_hdcp_status wait_for_rx_id_list(struct mod_hdcp *hdcp, |
578 | struct mod_hdcp_event_context *event_ctx, |
579 | struct mod_hdcp_transition_input_hdcp2 *input) |
580 | { |
581 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
582 | |
583 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
584 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ && |
585 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
586 | event_ctx->unexpected_event = 1; |
587 | goto out; |
588 | } |
589 | |
590 | if (!process_rxstatus(hdcp, event_ctx, input, status: &status)) |
591 | goto out; |
592 | if (!event_ctx->rx_id_list_ready) { |
593 | status = MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY; |
594 | goto out; |
595 | } |
596 | out: |
597 | return status; |
598 | } |
599 | |
600 | static enum mod_hdcp_status verify_rx_id_list_and_send_ack(struct mod_hdcp *hdcp, |
601 | struct mod_hdcp_event_context *event_ctx, |
602 | struct mod_hdcp_transition_input_hdcp2 *input) |
603 | { |
604 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
605 | |
606 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
607 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { |
608 | event_ctx->unexpected_event = 1; |
609 | goto out; |
610 | } |
611 | if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { |
612 | process_rxstatus(hdcp, event_ctx, input, status: &status); |
613 | goto out; |
614 | } |
615 | |
616 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_rx_id_list, |
617 | flag: &input->rx_id_list_read, |
618 | status: &status, hdcp, str: "receiver_id_list_read" )) |
619 | goto out; |
620 | if (!mod_hdcp_execute_and_set(func: check_device_count, |
621 | flag: &input->device_count_check, |
622 | status: &status, hdcp, str: "device_count_check" )) |
623 | goto out; |
624 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_rx_id_list, |
625 | flag: &input->rx_id_list_validation, |
626 | status: &status, hdcp, str: "rx_id_list_validation" )) |
627 | goto out; |
628 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_repeater_auth_ack, |
629 | flag: &input->repeater_auth_ack_write, |
630 | status: &status, hdcp, str: "repeater_auth_ack_write" )) |
631 | goto out; |
632 | out: |
633 | return status; |
634 | } |
635 | |
636 | static enum mod_hdcp_status send_stream_management(struct mod_hdcp *hdcp, |
637 | struct mod_hdcp_event_context *event_ctx, |
638 | struct mod_hdcp_transition_input_hdcp2 *input) |
639 | { |
640 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
641 | |
642 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
643 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { |
644 | event_ctx->unexpected_event = 1; |
645 | goto out; |
646 | } |
647 | if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { |
648 | process_rxstatus(hdcp, event_ctx, input, status: &status); |
649 | goto out; |
650 | } |
651 | |
652 | if (is_hdmi_dvi_sl_hdcp(hdcp)) { |
653 | if (!process_rxstatus(hdcp, event_ctx, input, status: &status)) |
654 | goto out; |
655 | if (event_ctx->rx_id_list_ready) |
656 | goto out; |
657 | } |
658 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_prepare_stream_management, |
659 | flag: &input->prepare_stream_manage, |
660 | status: &status, hdcp, str: "prepare_stream_manage" )) |
661 | goto out; |
662 | |
663 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_stream_manage, |
664 | flag: &input->stream_manage_write, |
665 | status: &status, hdcp, str: "stream_manage_write" )) |
666 | goto out; |
667 | out: |
668 | return status; |
669 | } |
670 | |
671 | static enum mod_hdcp_status validate_stream_ready(struct mod_hdcp *hdcp, |
672 | struct mod_hdcp_event_context *event_ctx, |
673 | struct mod_hdcp_transition_input_hdcp2 *input) |
674 | { |
675 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
676 | |
677 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
678 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ && |
679 | event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { |
680 | event_ctx->unexpected_event = 1; |
681 | goto out; |
682 | } |
683 | if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { |
684 | process_rxstatus(hdcp, event_ctx, input, status: &status); |
685 | goto out; |
686 | } |
687 | |
688 | if (is_hdmi_dvi_sl_hdcp(hdcp)) { |
689 | if (!process_rxstatus(hdcp, event_ctx, input, status: &status)) |
690 | goto out; |
691 | if (event_ctx->rx_id_list_ready) |
692 | goto out; |
693 | } |
694 | if (is_hdmi_dvi_sl_hdcp(hdcp)) |
695 | if (!mod_hdcp_execute_and_set(func: check_stream_ready_available, |
696 | flag: &input->stream_ready_available, |
697 | status: &status, hdcp, str: "stream_ready_available" )) |
698 | goto out; |
699 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_stream_ready, |
700 | flag: &input->stream_ready_read, |
701 | status: &status, hdcp, str: "stream_ready_read" )) |
702 | goto out; |
703 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_hdcp2_validate_stream_ready, |
704 | flag: &input->stream_ready_validation, |
705 | status: &status, hdcp, str: "stream_ready_validation" )) |
706 | goto out; |
707 | |
708 | out: |
709 | return status; |
710 | } |
711 | |
712 | static enum mod_hdcp_status determine_rx_hdcp_capable_dp(struct mod_hdcp *hdcp, |
713 | struct mod_hdcp_event_context *event_ctx, |
714 | struct mod_hdcp_transition_input_hdcp2 *input) |
715 | { |
716 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
717 | |
718 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { |
719 | event_ctx->unexpected_event = 1; |
720 | goto out; |
721 | } |
722 | |
723 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_read_rxcaps, |
724 | flag: &input->rx_caps_read_dp, |
725 | status: &status, hdcp, str: "rx_caps_read_dp" )) |
726 | goto out; |
727 | if (!mod_hdcp_execute_and_set(func: check_hdcp2_capable, |
728 | flag: &input->hdcp2_capable_check, status: &status, |
729 | hdcp, str: "hdcp2_capable_check" )) |
730 | goto out; |
731 | out: |
732 | return status; |
733 | } |
734 | |
735 | static enum mod_hdcp_status send_content_stream_type_dp(struct mod_hdcp *hdcp, |
736 | struct mod_hdcp_event_context *event_ctx, |
737 | struct mod_hdcp_transition_input_hdcp2 *input) |
738 | { |
739 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
740 | |
741 | if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && |
742 | event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { |
743 | event_ctx->unexpected_event = 1; |
744 | goto out; |
745 | } |
746 | |
747 | if (!process_rxstatus(hdcp, event_ctx, input, status: &status)) |
748 | goto out; |
749 | if (!mod_hdcp_execute_and_set(func: mod_hdcp_write_content_type, |
750 | flag: &input->content_stream_type_write, status: &status, |
751 | hdcp, str: "content_stream_type_write" )) |
752 | goto out; |
753 | out: |
754 | return status; |
755 | } |
756 | |
757 | enum mod_hdcp_status mod_hdcp_hdcp2_execution(struct mod_hdcp *hdcp, |
758 | struct mod_hdcp_event_context *event_ctx, |
759 | struct mod_hdcp_transition_input_hdcp2 *input) |
760 | { |
761 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
762 | |
763 | switch (current_state(hdcp)) { |
764 | case H2_A0_KNOWN_HDCP2_CAPABLE_RX: |
765 | status = known_hdcp2_capable_rx(hdcp, event_ctx, input); |
766 | break; |
767 | case H2_A1_SEND_AKE_INIT: |
768 | status = send_ake_init(hdcp, event_ctx, input); |
769 | break; |
770 | case H2_A1_VALIDATE_AKE_CERT: |
771 | status = validate_ake_cert(hdcp, event_ctx, input); |
772 | break; |
773 | case H2_A1_SEND_NO_STORED_KM: |
774 | status = send_no_stored_km(hdcp, event_ctx, input); |
775 | break; |
776 | case H2_A1_READ_H_PRIME: |
777 | status = read_h_prime(hdcp, event_ctx, input); |
778 | break; |
779 | case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: |
780 | status = read_pairing_info_and_validate_h_prime(hdcp, |
781 | event_ctx, input); |
782 | break; |
783 | case H2_A1_SEND_STORED_KM: |
784 | status = send_stored_km(hdcp, event_ctx, input); |
785 | break; |
786 | case H2_A1_VALIDATE_H_PRIME: |
787 | status = validate_h_prime(hdcp, event_ctx, input); |
788 | break; |
789 | case H2_A2_LOCALITY_CHECK: |
790 | status = locality_check(hdcp, event_ctx, input); |
791 | break; |
792 | case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER: |
793 | status = exchange_ks_and_test_for_repeater(hdcp, event_ctx, input); |
794 | break; |
795 | case H2_ENABLE_ENCRYPTION: |
796 | status = enable_encryption(hdcp, event_ctx, input); |
797 | break; |
798 | case H2_A5_AUTHENTICATED: |
799 | status = authenticated(hdcp, event_ctx, input); |
800 | break; |
801 | case H2_A6_WAIT_FOR_RX_ID_LIST: |
802 | status = wait_for_rx_id_list(hdcp, event_ctx, input); |
803 | break; |
804 | case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: |
805 | status = verify_rx_id_list_and_send_ack(hdcp, event_ctx, input); |
806 | break; |
807 | case H2_A9_SEND_STREAM_MANAGEMENT: |
808 | status = send_stream_management(hdcp, event_ctx, input); |
809 | break; |
810 | case H2_A9_VALIDATE_STREAM_READY: |
811 | status = validate_stream_ready(hdcp, event_ctx, input); |
812 | break; |
813 | default: |
814 | status = MOD_HDCP_STATUS_INVALID_STATE; |
815 | break; |
816 | } |
817 | |
818 | return status; |
819 | } |
820 | |
821 | enum mod_hdcp_status mod_hdcp_hdcp2_dp_execution(struct mod_hdcp *hdcp, |
822 | struct mod_hdcp_event_context *event_ctx, |
823 | struct mod_hdcp_transition_input_hdcp2 *input) |
824 | { |
825 | enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; |
826 | |
827 | switch (current_state(hdcp)) { |
828 | case D2_A0_DETERMINE_RX_HDCP_CAPABLE: |
829 | status = determine_rx_hdcp_capable_dp(hdcp, event_ctx, input); |
830 | break; |
831 | case D2_A1_SEND_AKE_INIT: |
832 | status = send_ake_init(hdcp, event_ctx, input); |
833 | break; |
834 | case D2_A1_VALIDATE_AKE_CERT: |
835 | status = validate_ake_cert(hdcp, event_ctx, input); |
836 | break; |
837 | case D2_A1_SEND_NO_STORED_KM: |
838 | status = send_no_stored_km(hdcp, event_ctx, input); |
839 | break; |
840 | case D2_A1_READ_H_PRIME: |
841 | status = read_h_prime(hdcp, event_ctx, input); |
842 | break; |
843 | case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: |
844 | status = read_pairing_info_and_validate_h_prime(hdcp, |
845 | event_ctx, input); |
846 | break; |
847 | case D2_A1_SEND_STORED_KM: |
848 | status = send_stored_km(hdcp, event_ctx, input); |
849 | break; |
850 | case D2_A1_VALIDATE_H_PRIME: |
851 | status = validate_h_prime(hdcp, event_ctx, input); |
852 | break; |
853 | case D2_A2_LOCALITY_CHECK: |
854 | status = locality_check(hdcp, event_ctx, input); |
855 | break; |
856 | case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER: |
857 | status = exchange_ks_and_test_for_repeater(hdcp, |
858 | event_ctx, input); |
859 | break; |
860 | case D2_SEND_CONTENT_STREAM_TYPE: |
861 | status = send_content_stream_type_dp(hdcp, event_ctx, input); |
862 | break; |
863 | case D2_ENABLE_ENCRYPTION: |
864 | status = enable_encryption(hdcp, event_ctx, input); |
865 | break; |
866 | case D2_A5_AUTHENTICATED: |
867 | status = authenticated(hdcp, event_ctx, input); |
868 | break; |
869 | case D2_A6_WAIT_FOR_RX_ID_LIST: |
870 | status = wait_for_rx_id_list(hdcp, event_ctx, input); |
871 | break; |
872 | case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: |
873 | status = verify_rx_id_list_and_send_ack(hdcp, event_ctx, input); |
874 | break; |
875 | case D2_A9_SEND_STREAM_MANAGEMENT: |
876 | status = send_stream_management(hdcp, event_ctx, input); |
877 | break; |
878 | case D2_A9_VALIDATE_STREAM_READY: |
879 | status = validate_stream_ready(hdcp, event_ctx, input); |
880 | break; |
881 | default: |
882 | status = MOD_HDCP_STATUS_INVALID_STATE; |
883 | break; |
884 | } |
885 | |
886 | return status; |
887 | } |
888 | |