Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2019 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "hdcp.h"
0027 
0028 static void push_error_status(struct mod_hdcp *hdcp,
0029         enum mod_hdcp_status status)
0030 {
0031     struct mod_hdcp_trace *trace = &hdcp->connection.trace;
0032 
0033     if (trace->error_count < MAX_NUM_OF_ERROR_TRACE) {
0034         trace->errors[trace->error_count].status = status;
0035         trace->errors[trace->error_count].state_id = hdcp->state.id;
0036         trace->error_count++;
0037         HDCP_ERROR_TRACE(hdcp, status);
0038     }
0039 
0040     if (is_hdcp1(hdcp)) {
0041         hdcp->connection.hdcp1_retry_count++;
0042         if (hdcp->connection.hdcp1_retry_count == MAX_NUM_OF_ATTEMPTS)
0043             hdcp->connection.link.adjust.hdcp1.disable = 1;
0044     } else if (is_hdcp2(hdcp)) {
0045         hdcp->connection.hdcp2_retry_count++;
0046         if (hdcp->connection.hdcp2_retry_count == MAX_NUM_OF_ATTEMPTS)
0047             hdcp->connection.link.adjust.hdcp2.disable = 1;
0048     }
0049 }
0050 
0051 static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp)
0052 {
0053     int i, is_auth_needed = 0;
0054 
0055     /* if all displays on the link don't need authentication,
0056      * hdcp is not desired
0057      */
0058     for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
0059         if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
0060                 hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) {
0061             is_auth_needed = 1;
0062             break;
0063         }
0064     }
0065 
0066     return is_auth_needed &&
0067             !hdcp->connection.link.adjust.hdcp1.disable &&
0068             !hdcp->connection.is_hdcp1_revoked;
0069 }
0070 
0071 static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp)
0072 {
0073     int i, is_auth_needed = 0;
0074 
0075     /* if all displays on the link don't need authentication,
0076      * hdcp is not desired
0077      */
0078     for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
0079         if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_INACTIVE &&
0080                 hdcp->displays[i].adjust.disable != MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION) {
0081             is_auth_needed = 1;
0082             break;
0083         }
0084     }
0085 
0086     return is_auth_needed &&
0087             !hdcp->connection.link.adjust.hdcp2.disable &&
0088             !hdcp->connection.is_hdcp2_revoked;
0089 }
0090 
0091 static enum mod_hdcp_status execution(struct mod_hdcp *hdcp,
0092         struct mod_hdcp_event_context *event_ctx,
0093         union mod_hdcp_transition_input *input)
0094 {
0095     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0096 
0097     if (is_in_initialized_state(hdcp)) {
0098         if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
0099             event_ctx->unexpected_event = 1;
0100             goto out;
0101         }
0102         /* initialize transition input */
0103         memset(input, 0, sizeof(union mod_hdcp_transition_input));
0104     } else if (is_in_cp_not_desired_state(hdcp)) {
0105         if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) {
0106             event_ctx->unexpected_event = 1;
0107             goto out;
0108         }
0109     } else if (is_in_hdcp1_states(hdcp)) {
0110         status = mod_hdcp_hdcp1_execution(hdcp, event_ctx, &input->hdcp1);
0111     } else if (is_in_hdcp1_dp_states(hdcp)) {
0112         status = mod_hdcp_hdcp1_dp_execution(hdcp,
0113                 event_ctx, &input->hdcp1);
0114     } else if (is_in_hdcp2_states(hdcp)) {
0115         status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2);
0116     } else if (is_in_hdcp2_dp_states(hdcp)) {
0117         status = mod_hdcp_hdcp2_dp_execution(hdcp,
0118                 event_ctx, &input->hdcp2);
0119     } else {
0120         event_ctx->unexpected_event = 1;
0121         goto out;
0122     }
0123 out:
0124     return status;
0125 }
0126 
0127 static enum mod_hdcp_status transition(struct mod_hdcp *hdcp,
0128         struct mod_hdcp_event_context *event_ctx,
0129         union mod_hdcp_transition_input *input,
0130         struct mod_hdcp_output *output)
0131 {
0132     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0133 
0134     if (event_ctx->unexpected_event)
0135         goto out;
0136 
0137     if (is_in_initialized_state(hdcp)) {
0138         if (is_dp_hdcp(hdcp))
0139             if (is_cp_desired_hdcp2(hdcp)) {
0140                 callback_in_ms(0, output);
0141                 set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE);
0142             } else if (is_cp_desired_hdcp1(hdcp)) {
0143                 callback_in_ms(0, output);
0144                 set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE);
0145             } else {
0146                 callback_in_ms(0, output);
0147                 set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
0148                 set_auth_complete(hdcp, output);
0149             }
0150         else if (is_hdmi_dvi_sl_hdcp(hdcp))
0151             if (is_cp_desired_hdcp2(hdcp)) {
0152                 callback_in_ms(0, output);
0153                 set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX);
0154             } else if (is_cp_desired_hdcp1(hdcp)) {
0155                 callback_in_ms(0, output);
0156                 set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX);
0157             } else {
0158                 callback_in_ms(0, output);
0159                 set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
0160                 set_auth_complete(hdcp, output);
0161             }
0162         else {
0163             callback_in_ms(0, output);
0164             set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED);
0165             set_auth_complete(hdcp, output);
0166         }
0167     } else if (is_in_cp_not_desired_state(hdcp)) {
0168         increment_stay_counter(hdcp);
0169     } else if (is_in_hdcp1_states(hdcp)) {
0170         status = mod_hdcp_hdcp1_transition(hdcp,
0171                 event_ctx, &input->hdcp1, output);
0172     } else if (is_in_hdcp1_dp_states(hdcp)) {
0173         status = mod_hdcp_hdcp1_dp_transition(hdcp,
0174                 event_ctx, &input->hdcp1, output);
0175     } else if (is_in_hdcp2_states(hdcp)) {
0176         status = mod_hdcp_hdcp2_transition(hdcp,
0177                 event_ctx, &input->hdcp2, output);
0178     } else if (is_in_hdcp2_dp_states(hdcp)) {
0179         status = mod_hdcp_hdcp2_dp_transition(hdcp,
0180                 event_ctx, &input->hdcp2, output);
0181     } else {
0182         status = MOD_HDCP_STATUS_INVALID_STATE;
0183     }
0184 out:
0185     return status;
0186 }
0187 
0188 static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp,
0189         struct mod_hdcp_output *output)
0190 {
0191     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0192 
0193     if (is_hdcp1(hdcp)) {
0194         if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) {
0195             /* TODO - update psp to unify create session failure
0196              * recovery between hdcp1 and 2.
0197              */
0198             mod_hdcp_hdcp1_destroy_session(hdcp);
0199 
0200         }
0201 
0202         HDCP_TOP_RESET_AUTH_TRACE(hdcp);
0203         memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
0204         memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
0205         set_state_id(hdcp, output, HDCP_INITIALIZED);
0206     } else if (is_hdcp2(hdcp)) {
0207         if (hdcp->auth.trans_input.hdcp2.create_session == PASS) {
0208             status = mod_hdcp_hdcp2_destroy_session(hdcp);
0209             if (status != MOD_HDCP_STATUS_SUCCESS) {
0210                 output->callback_needed = 0;
0211                 output->watchdog_timer_needed = 0;
0212                 goto out;
0213             }
0214         }
0215 
0216         HDCP_TOP_RESET_AUTH_TRACE(hdcp);
0217         memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
0218         memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
0219         set_state_id(hdcp, output, HDCP_INITIALIZED);
0220     } else if (is_in_cp_not_desired_state(hdcp)) {
0221         HDCP_TOP_RESET_AUTH_TRACE(hdcp);
0222         memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication));
0223         memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state));
0224         set_state_id(hdcp, output, HDCP_INITIALIZED);
0225     }
0226 
0227 out:
0228     /* stop callback and watchdog requests from previous authentication*/
0229     output->watchdog_timer_stop = 1;
0230     output->callback_stop = 1;
0231     return status;
0232 }
0233 
0234 static enum mod_hdcp_status reset_connection(struct mod_hdcp *hdcp,
0235         struct mod_hdcp_output *output)
0236 {
0237     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0238 
0239     memset(output, 0, sizeof(struct mod_hdcp_output));
0240 
0241     status = reset_authentication(hdcp, output);
0242     if (status != MOD_HDCP_STATUS_SUCCESS)
0243         goto out;
0244 
0245     if (current_state(hdcp) != HDCP_UNINITIALIZED) {
0246         HDCP_TOP_RESET_CONN_TRACE(hdcp);
0247         set_state_id(hdcp, output, HDCP_UNINITIALIZED);
0248     }
0249     memset(&hdcp->connection, 0, sizeof(hdcp->connection));
0250 out:
0251     return status;
0252 }
0253 
0254 static enum mod_hdcp_status update_display_adjustments(struct mod_hdcp *hdcp,
0255         struct mod_hdcp_display *display,
0256         struct mod_hdcp_display_adjustment *adj)
0257 {
0258     enum mod_hdcp_status status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
0259 
0260     if (is_in_authenticated_states(hdcp) &&
0261             is_dp_mst_hdcp(hdcp) &&
0262             display->adjust.disable == true &&
0263             adj->disable == false) {
0264         display->adjust.disable = false;
0265         if (is_hdcp1(hdcp))
0266             status = mod_hdcp_hdcp1_enable_dp_stream_encryption(hdcp);
0267         else if (is_hdcp2(hdcp))
0268             status = mod_hdcp_hdcp2_enable_dp_stream_encryption(hdcp);
0269 
0270         if (status != MOD_HDCP_STATUS_SUCCESS)
0271             display->adjust.disable = true;
0272     }
0273 
0274     if (status == MOD_HDCP_STATUS_SUCCESS &&
0275         memcmp(adj, &display->adjust,
0276         sizeof(struct mod_hdcp_display_adjustment)) != 0)
0277         status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
0278 
0279     return status;
0280 }
0281 /*
0282  * Implementation of functions in mod_hdcp.h
0283  */
0284 size_t mod_hdcp_get_memory_size(void)
0285 {
0286     return sizeof(struct mod_hdcp);
0287 }
0288 
0289 enum mod_hdcp_status mod_hdcp_setup(struct mod_hdcp *hdcp,
0290         struct mod_hdcp_config *config)
0291 {
0292     struct mod_hdcp_output output;
0293     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0294 
0295     memset(&output, 0, sizeof(output));
0296     hdcp->config = *config;
0297     HDCP_TOP_INTERFACE_TRACE(hdcp);
0298     status = reset_connection(hdcp, &output);
0299     if (status != MOD_HDCP_STATUS_SUCCESS)
0300         push_error_status(hdcp, status);
0301     return status;
0302 }
0303 
0304 enum mod_hdcp_status mod_hdcp_teardown(struct mod_hdcp *hdcp)
0305 {
0306     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0307     struct mod_hdcp_output output;
0308 
0309     HDCP_TOP_INTERFACE_TRACE(hdcp);
0310     memset(&output, 0,  sizeof(output));
0311     status = reset_connection(hdcp, &output);
0312     if (status == MOD_HDCP_STATUS_SUCCESS)
0313         memset(hdcp, 0, sizeof(struct mod_hdcp));
0314     else
0315         push_error_status(hdcp, status);
0316     return status;
0317 }
0318 
0319 enum mod_hdcp_status mod_hdcp_add_display(struct mod_hdcp *hdcp,
0320         struct mod_hdcp_link *link, struct mod_hdcp_display *display,
0321         struct mod_hdcp_output *output)
0322 {
0323     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0324     struct mod_hdcp_display *display_container = NULL;
0325 
0326     HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, display->index);
0327     memset(output, 0, sizeof(struct mod_hdcp_output));
0328 
0329     /* skip inactive display */
0330     if (display->state != MOD_HDCP_DISPLAY_ACTIVE) {
0331         status = MOD_HDCP_STATUS_SUCCESS;
0332         goto out;
0333     }
0334 
0335     /* check existing display container */
0336     if (get_active_display_at_index(hdcp, display->index)) {
0337         status = MOD_HDCP_STATUS_SUCCESS;
0338         goto out;
0339     }
0340 
0341     /* find an empty display container */
0342     display_container = get_empty_display_container(hdcp);
0343     if (!display_container) {
0344         status = MOD_HDCP_STATUS_DISPLAY_OUT_OF_BOUND;
0345         goto out;
0346     }
0347 
0348     /* reset existing authentication status */
0349     status = reset_authentication(hdcp, output);
0350     if (status != MOD_HDCP_STATUS_SUCCESS)
0351         goto out;
0352 
0353     /* reset retry counters */
0354     reset_retry_counts(hdcp);
0355 
0356     /* reset error trace */
0357     memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
0358 
0359     /* add display to connection */
0360     hdcp->connection.link = *link;
0361     *display_container = *display;
0362     status = mod_hdcp_add_display_to_topology(hdcp, display_container);
0363 
0364     if (status != MOD_HDCP_STATUS_SUCCESS)
0365         goto out;
0366 
0367     /* request authentication */
0368     if (current_state(hdcp) != HDCP_INITIALIZED)
0369         set_state_id(hdcp, output, HDCP_INITIALIZED);
0370     callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000, output);
0371 out:
0372     if (status != MOD_HDCP_STATUS_SUCCESS)
0373         push_error_status(hdcp, status);
0374 
0375     return status;
0376 }
0377 
0378 enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp,
0379         uint8_t index, struct mod_hdcp_output *output)
0380 {
0381     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0382     struct mod_hdcp_display *display = NULL;
0383 
0384     HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index);
0385     memset(output, 0, sizeof(struct mod_hdcp_output));
0386 
0387     /* find display in connection */
0388     display = get_active_display_at_index(hdcp, index);
0389     if (!display) {
0390         status = MOD_HDCP_STATUS_SUCCESS;
0391         goto out;
0392     }
0393 
0394     /* stop current authentication */
0395     status = reset_authentication(hdcp, output);
0396     if (status != MOD_HDCP_STATUS_SUCCESS)
0397         goto out;
0398 
0399     /* clear retry counters */
0400     reset_retry_counts(hdcp);
0401 
0402     /* reset error trace */
0403     memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
0404 
0405     /* remove display */
0406     status = mod_hdcp_remove_display_from_topology(hdcp, index);
0407     if (status != MOD_HDCP_STATUS_SUCCESS)
0408         goto out;
0409     memset(display, 0, sizeof(struct mod_hdcp_display));
0410 
0411     /* request authentication when connection is not reset */
0412     if (current_state(hdcp) != HDCP_UNINITIALIZED)
0413         callback_in_ms(hdcp->connection.link.adjust.auth_delay * 1000,
0414                 output);
0415 out:
0416     if (status != MOD_HDCP_STATUS_SUCCESS)
0417         push_error_status(hdcp, status);
0418     return status;
0419 }
0420 
0421 enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp,
0422         uint8_t index,
0423         struct mod_hdcp_link_adjustment *link_adjust,
0424         struct mod_hdcp_display_adjustment *display_adjust,
0425         struct mod_hdcp_output *output)
0426 {
0427     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0428     struct mod_hdcp_display *display = NULL;
0429 
0430     HDCP_TOP_INTERFACE_TRACE_WITH_INDEX(hdcp, index);
0431     memset(output, 0, sizeof(struct mod_hdcp_output));
0432 
0433     /* find display in connection */
0434     display = get_active_display_at_index(hdcp, index);
0435     if (!display) {
0436         status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
0437         goto out;
0438     }
0439 
0440     /* skip if no changes */
0441     if (memcmp(link_adjust, &hdcp->connection.link.adjust,
0442             sizeof(struct mod_hdcp_link_adjustment)) == 0 &&
0443             memcmp(display_adjust, &display->adjust,
0444                     sizeof(struct mod_hdcp_display_adjustment)) == 0) {
0445         status = MOD_HDCP_STATUS_SUCCESS;
0446         goto out;
0447     }
0448 
0449     if (memcmp(link_adjust, &hdcp->connection.link.adjust,
0450             sizeof(struct mod_hdcp_link_adjustment)) == 0 &&
0451             memcmp(display_adjust, &display->adjust,
0452                     sizeof(struct mod_hdcp_display_adjustment)) != 0) {
0453         status = update_display_adjustments(hdcp, display, display_adjust);
0454         if (status != MOD_HDCP_STATUS_NOT_IMPLEMENTED)
0455             goto out;
0456     }
0457 
0458     /* stop current authentication */
0459     status = reset_authentication(hdcp, output);
0460     if (status != MOD_HDCP_STATUS_SUCCESS)
0461         goto out;
0462 
0463     /* clear retry counters */
0464     reset_retry_counts(hdcp);
0465 
0466     /* reset error trace */
0467     memset(&hdcp->connection.trace, 0, sizeof(hdcp->connection.trace));
0468 
0469     /* set new adjustment */
0470     hdcp->connection.link.adjust = *link_adjust;
0471     display->adjust = *display_adjust;
0472 
0473     /* request authentication when connection is not reset */
0474     if (current_state(hdcp) != HDCP_UNINITIALIZED)
0475         /* wait 100ms to debounce simultaneous updates for different indices */
0476         callback_in_ms(100, output);
0477 
0478 out:
0479     if (status != MOD_HDCP_STATUS_SUCCESS)
0480         push_error_status(hdcp, status);
0481     return status;
0482 }
0483 
0484 enum mod_hdcp_status mod_hdcp_query_display(struct mod_hdcp *hdcp,
0485         uint8_t index, struct mod_hdcp_display_query *query)
0486 {
0487     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0488     struct mod_hdcp_display *display = NULL;
0489 
0490     /* find display in connection */
0491     display = get_active_display_at_index(hdcp, index);
0492     if (!display) {
0493         status = MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
0494         goto out;
0495     }
0496 
0497     /* populate query */
0498     query->link = &hdcp->connection.link;
0499     query->display = display;
0500     query->trace = &hdcp->connection.trace;
0501     query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
0502 
0503     if (is_display_encryption_enabled(display)) {
0504         if (is_hdcp1(hdcp)) {
0505             query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON;
0506         } else if (is_hdcp2(hdcp)) {
0507             if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0)
0508                 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON;
0509             else if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1)
0510                 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON;
0511             else
0512                 query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON;
0513         }
0514     } else {
0515         query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
0516     }
0517 
0518 out:
0519     return status;
0520 }
0521 
0522 enum mod_hdcp_status mod_hdcp_reset_connection(struct mod_hdcp *hdcp,
0523         struct mod_hdcp_output *output)
0524 {
0525     enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
0526 
0527     HDCP_TOP_INTERFACE_TRACE(hdcp);
0528     status = reset_connection(hdcp, output);
0529     if (status != MOD_HDCP_STATUS_SUCCESS)
0530         push_error_status(hdcp, status);
0531 
0532     return status;
0533 }
0534 
0535 enum mod_hdcp_status mod_hdcp_process_event(struct mod_hdcp *hdcp,
0536         enum mod_hdcp_event event, struct mod_hdcp_output *output)
0537 {
0538     enum mod_hdcp_status exec_status, trans_status, reset_status, status;
0539     struct mod_hdcp_event_context event_ctx;
0540 
0541     HDCP_EVENT_TRACE(hdcp, event);
0542     memset(output, 0, sizeof(struct mod_hdcp_output));
0543     memset(&event_ctx, 0, sizeof(struct mod_hdcp_event_context));
0544     event_ctx.event = event;
0545 
0546     /* execute and transition */
0547     exec_status = execution(hdcp, &event_ctx, &hdcp->auth.trans_input);
0548     trans_status = transition(
0549             hdcp, &event_ctx, &hdcp->auth.trans_input, output);
0550     if (trans_status == MOD_HDCP_STATUS_SUCCESS) {
0551         status = MOD_HDCP_STATUS_SUCCESS;
0552     } else if (exec_status == MOD_HDCP_STATUS_SUCCESS) {
0553         status = MOD_HDCP_STATUS_INTERNAL_POLICY_FAILURE;
0554         push_error_status(hdcp, status);
0555     } else {
0556         status = exec_status;
0557         push_error_status(hdcp, status);
0558     }
0559 
0560     /* reset authentication if needed */
0561     if (trans_status == MOD_HDCP_STATUS_RESET_NEEDED) {
0562         mod_hdcp_log_ddc_trace(hdcp);
0563         reset_status = reset_authentication(hdcp, output);
0564         if (reset_status != MOD_HDCP_STATUS_SUCCESS)
0565             push_error_status(hdcp, reset_status);
0566     }
0567 
0568     /* Clear CP_IRQ status if needed */
0569     if (event_ctx.event == MOD_HDCP_EVENT_CPIRQ) {
0570         status = mod_hdcp_clear_cp_irq_status(hdcp);
0571         if (status != MOD_HDCP_STATUS_SUCCESS)
0572             push_error_status(hdcp, status);
0573     }
0574 
0575     return status;
0576 }
0577 
0578 enum mod_hdcp_operation_mode mod_hdcp_signal_type_to_operation_mode(
0579         enum signal_type signal)
0580 {
0581     enum mod_hdcp_operation_mode mode = MOD_HDCP_MODE_OFF;
0582 
0583     switch (signal) {
0584     case SIGNAL_TYPE_DVI_SINGLE_LINK:
0585     case SIGNAL_TYPE_HDMI_TYPE_A:
0586         mode = MOD_HDCP_MODE_DEFAULT;
0587         break;
0588     case SIGNAL_TYPE_EDP:
0589     case SIGNAL_TYPE_DISPLAY_PORT:
0590     case SIGNAL_TYPE_DISPLAY_PORT_MST:
0591         mode = MOD_HDCP_MODE_DP;
0592         break;
0593     default:
0594         break;
0595     }
0596 
0597     return mode;
0598 }