/*----------------------------------------------------------------------------- * Function: hdcp_wq_start_authentication *----------------------------------------------------------------------------- */ static void hdcp_wq_start_authentication(void) { int status = HDCP_OK; hdcp.hdcp_state = HDCP_AUTHENTICATION_START; printk(KERN_INFO "HDCP: authentication start\n"); /* Step 1 part 1 (until R0 calc delay) */ status = hdcp_lib_step1_start(); if (status == -HDCP_AKSV_ERROR) { hdcp_wq_authentication_failure(); } else if (status == -HDCP_CANCELLED_AUTH) { DBG("Authentication step 1 cancelled."); return; } else if (status != HDCP_OK) { hdcp_wq_authentication_failure(); } else { hdcp.hdcp_state = HDCP_WAIT_R0_DELAY; hdcp.auth_state = HDCP_STATE_AUTH_1ST_STEP; hdcp.pending_wq_event = hdcp_submit_work(HDCP_R0_EXP_EVENT, HDCP_R0_DELAY); } }
/*----------------------------------------------------------------------------- * Function: hdcp_wq_step2_authentication *----------------------------------------------------------------------------- */ static void hdcp_wq_step2_authentication(void) { int status = HDCP_OK; /* KSV list timeout is running and should be canceled */ hdcp_cancel_work(&hdcp.pending_wq_event); status = hdcp_lib_step2(); if (status == -HDCP_CANCELLED_AUTH) { DBG("Authentication step 2 cancelled."); return; } else if (status < 0) hdcp_wq_authentication_failure(); else { printk(KERN_INFO "HDCP: (Repeater) authentication step 2 " "successful\n"); hdcp.hdcp_state = HDCP_LINK_INTEGRITY_CHECK; hdcp.auth_state = HDCP_STATE_AUTH_3RD_STEP; /* Restore retry counter */ if (hdcp.en_ctrl->nb_retry == 0) hdcp.retry_cnt = HDCP_INFINITE_REAUTH; else hdcp.retry_cnt = hdcp.en_ctrl->nb_retry; } }
/*----------------------------------------------------------------------------- * Function: hdcp_wq_check_bksv *----------------------------------------------------------------------------- */ static void hdcp_wq_check_bksv(void) { int status = HDCP_OK; DBG("Check BKSV start"); status = rk30_hdcp_check_bksv(hdcp); if (status != HDCP_OK) { printk(KERN_INFO "HDCP: Check BKSV failed"); hdcp->retry_cnt = 0; hdcp_wq_authentication_failure(); } else { DBG("HDCP: Check BKSV successful"); hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK; /* Restore retry counter */ if(hdcp->retry_times == 0) hdcp->retry_cnt = HDCP_INFINITE_REAUTH; else hdcp->retry_cnt = hdcp->retry_times; } }
/*----------------------------------------------------------------------------- * Function: hdcp_wq_start_authentication *----------------------------------------------------------------------------- */ static void hdcp_wq_start_authentication(void) { int status = HDCP_OK; hdcp->hdcp_state = HDCP_AUTHENTICATION_START; DBG("HDCP: authentication start"); status = rk30_hdcp_start_authentication(hdcp); if (status != HDCP_OK) { DBG("HDCP: authentication failed"); hdcp_wq_authentication_failure(); } else { hdcp->hdcp_state = HDCP_WAIT_KSV_LIST; } }
/*----------------------------------------------------------------------------- * Function: hdcp_wq_check_r0 *----------------------------------------------------------------------------- */ static void hdcp_wq_check_r0(void) { int status = hdcp_lib_step1_r0_check(); if (status == -HDCP_CANCELLED_AUTH) { DBG("Authentication step 1/R0 cancelled."); return; } else if (status < 0) hdcp_wq_authentication_failure(); else { if (hdcp_lib_check_repeater_bit_in_tx()) { /* Repeater */ printk(KERN_INFO "HDCP: authentication step 1 " "successful - Repeater\n"); hdcp.hdcp_state = HDCP_WAIT_KSV_LIST; hdcp.auth_state = HDCP_STATE_AUTH_2ND_STEP; hdcp.pending_wq_event = hdcp_submit_work(HDCP_KSV_TIMEOUT_EVENT, HDCP_KSV_TIMEOUT_DELAY); } else { /* Receiver */ printk(KERN_INFO "HDCP: authentication step 1 " "successful - Receiver\n"); hdcp.hdcp_state = HDCP_LINK_INTEGRITY_CHECK; hdcp.auth_state = HDCP_STATE_AUTH_3RD_STEP; /* Restore retry counter */ if (hdcp.en_ctrl->nb_retry == 0) hdcp.retry_cnt = HDCP_INFINITE_REAUTH; else hdcp.retry_cnt = hdcp.en_ctrl->nb_retry; } } }
/*----------------------------------------------------------------------------- * Function: hdcp_work_queue *----------------------------------------------------------------------------- */ static void hdcp_work_queue(struct work_struct *work) { struct hdcp_delayed_work *hdcp_w = container_of(work, struct hdcp_delayed_work, work.work); int event = hdcp_w->event; mutex_lock(&hdcp.lock); hdcp_request_dss(); DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d auth=%d evt= %x %d" " hdcp_ctrl=%02x", jiffies_to_msecs(jiffies), hdcp.hdmi_state, hdcp.hdcp_state, hdcp.auth_state, (event & 0xFF00) >> 8, event & 0xFF, RD_REG_32(hdcp.hdmi_wp_base_addr + HDMI_IP_CORE_SYSTEM, HDMI_IP_CORE_SYSTEM__HDCP_CTRL)); /* Clear pending_wq_event * In case a delayed work is scheduled from the state machine * "pending_wq_event" is used to memorize pointer on the event to be * able to cancel any pending work in case HDCP is disabled */ if (event & HDCP_WORKQUEUE_SRC) hdcp.pending_wq_event = 0; /* First handle HDMI state */ if (event == HDCP_START_FRAME_EVENT) { hdcp.pending_start = 0; hdcp.hdmi_state = HDMI_STARTED; } /**********************/ /* HDCP state machine */ /**********************/ switch (hdcp.hdcp_state) { /* State */ /*********/ case HDCP_DISABLED: /* HDCP enable control or re-authentication event */ if (event == HDCP_ENABLE_CTL) { if (hdcp.en_ctrl->nb_retry == 0) hdcp.retry_cnt = HDCP_INFINITE_REAUTH; else hdcp.retry_cnt = hdcp.en_ctrl->nb_retry; if (hdcp.hdmi_state == HDMI_STARTED) hdcp_wq_start_authentication(); else hdcp.hdcp_state = HDCP_ENABLE_PENDING; } break; /* State */ /*********/ case HDCP_ENABLE_PENDING: /* HDMI start frame event */ if (event == HDCP_START_FRAME_EVENT) hdcp_wq_start_authentication(); break; /* State */ /*********/ case HDCP_AUTHENTICATION_START: /* Re-authentication */ if (event == HDCP_AUTH_REATT_EVENT) hdcp_wq_start_authentication(); break; /* State */ /*********/ case HDCP_WAIT_R0_DELAY: /* R0 timer elapsed */ if (event == HDCP_R0_EXP_EVENT) hdcp_wq_check_r0(); break; /* State */ /*********/ case HDCP_WAIT_KSV_LIST: /* Ri failure */ if (event == HDCP_RI_FAIL_EVENT) { printk(KERN_INFO "HDCP: Ri check failure\n"); hdcp_wq_authentication_failure(); } /* KSV list ready event */ else if (event == HDCP_KSV_LIST_RDY_EVENT) hdcp_wq_step2_authentication(); /* Timeout */ else if (event == HDCP_KSV_TIMEOUT_EVENT) { printk(KERN_INFO "HDCP: BCAPS polling timeout\n"); hdcp_wq_authentication_failure(); } break; /* State */ /*********/ case HDCP_LINK_INTEGRITY_CHECK: /* Ri failure */ if (event == HDCP_RI_FAIL_EVENT) { printk(KERN_INFO "HDCP: Ri check failure\n"); hdcp_wq_authentication_failure(); } break; default: printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); break; } kfree(hdcp_w); hdcp_w = 0; if (event == HDCP_START_FRAME_EVENT) hdcp.pending_start = 0; if (event == HDCP_KSV_LIST_RDY_EVENT || event == HDCP_R0_EXP_EVENT) { hdcp.pending_wq_event = 0; } DBG("hdcp_work_queue() - END - %u hdmi=%d hdcp=%d auth=%d evt=%x %d ", jiffies_to_msecs(jiffies), hdcp.hdmi_state, hdcp.hdcp_state, hdcp.auth_state, (event & 0xFF00) >> 8, event & 0xFF); hdcp_release_dss(); mutex_unlock(&hdcp.lock); }
/*----------------------------------------------------------------------------- * Function: hdcp_work_queue *----------------------------------------------------------------------------- */ static void hdcp_work_queue(struct work_struct *work) { struct hdcp_delayed_work *hdcp_w = container_of(work, struct hdcp_delayed_work, work.work); int event = hdcp_w->event; mutex_lock(&hdcp->lock); DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d", jiffies_to_msecs(jiffies), hdcp->hdmi_state, hdcp->hdcp_state, (event & 0xFF00) >> 8, event & 0xFF); if(event == HDCP_STOP_FRAME_EVENT) { hdcp->hdmi_state = HDMI_STOPPED; } if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) { hdcp_wq_disable(event); } if (event & HDCP_WORKQUEUE_SRC) hdcp->pending_wq_event = 0; /* First handle HDMI state */ if (event == HDCP_START_FRAME_EVENT) { hdcp->pending_start = 0; hdcp->hdmi_state = HDMI_STARTED; } /**********************/ /* HDCP state machine */ /**********************/ switch (hdcp->hdcp_state) { case HDCP_DISABLED: /* HDCP enable control or re-authentication event */ if (event == HDCP_ENABLE_CTL) { if(hdcp->retry_times == 0) hdcp->retry_cnt = HDCP_INFINITE_REAUTH; else hdcp->retry_cnt = hdcp->retry_times; if (hdcp->hdmi_state == HDMI_STARTED) hdcp_wq_start_authentication(); else hdcp->hdcp_state = HDCP_ENABLE_PENDING; } break; case HDCP_ENABLE_PENDING: /* HDMI start frame event */ if (event == HDCP_START_FRAME_EVENT) hdcp_wq_start_authentication(); break; case HDCP_AUTHENTICATION_START: /* Re-authentication */ if (event == HDCP_AUTH_REATT_EVENT) hdcp_wq_start_authentication(); break; case HDCP_WAIT_KSV_LIST: /* KSV failure */ if (event == HDCP_FAIL_EVENT) { printk(KERN_INFO "HDCP: KSV switch failure\n"); hdcp_wq_authentication_failure(); } /* KSV list ready event */ else if (event == HDCP_KSV_LIST_RDY_EVENT) hdcp_wq_check_bksv(); break; case HDCP_LINK_INTEGRITY_CHECK: /* Ri failure */ if (event == HDCP_FAIL_EVENT) { printk(KERN_INFO "HDCP: Ri check failure\n"); hdcp_wq_authentication_failure(); } else if(event == HDCP_AUTH_PASS_EVENT) hdcp_wq_authentication_sucess(); break; default: printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); break; } kfree(hdcp_w); if(event == HDCP_STOP_FRAME_EVENT) complete(&hdcp->complete); mutex_unlock(&hdcp->lock); }