msm: mdss: hdmi: hdcp2p2: add tethered support
Provide user an option to let the HDCP2.2 authentication run on main thread. Avoid processing on module threads thus avoiding any scheduling delays. The user may choose to switch to this mode based on its requirements. Change-Id: I76ec4a18f0fc52e99bbe76b6707511d3af6151f3 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
This commit is contained in:
parent
d27317a651
commit
bd9d0784e8
5 changed files with 426 additions and 240 deletions
|
@ -126,11 +126,12 @@
|
||||||
/*This API calls the library deinit function */
|
/*This API calls the library deinit function */
|
||||||
#define HDCP_LIB_DEINIT SERVICE_TXMTR_CREATE_CMD(12)
|
#define HDCP_LIB_DEINIT SERVICE_TXMTR_CREATE_CMD(12)
|
||||||
|
|
||||||
enum hdcp_app_status {
|
#define HDCP_LIB_EXECUTE(x) {\
|
||||||
LOADED,
|
if (handle->tethered)\
|
||||||
UNLOADED,
|
hdcp_lib_##x(handle);\
|
||||||
FAILED = -1,
|
else\
|
||||||
};
|
queue_kthread_work(&handle->worker, &handle->wk_##x);\
|
||||||
|
}
|
||||||
|
|
||||||
enum hdcp_state {
|
enum hdcp_state {
|
||||||
HDCP_STATE_INIT = 0x00,
|
HDCP_STATE_INIT = 0x00,
|
||||||
|
@ -337,12 +338,12 @@ struct hdcp_lib_handle {
|
||||||
bool feature_supported;
|
bool feature_supported;
|
||||||
void *client_ctx;
|
void *client_ctx;
|
||||||
struct hdcp_client_ops *client_ops;
|
struct hdcp_client_ops *client_ops;
|
||||||
struct mutex hdcp_lock;
|
|
||||||
struct mutex msg_lock;
|
struct mutex msg_lock;
|
||||||
struct mutex wakeup_mutex;
|
struct mutex wakeup_mutex;
|
||||||
enum hdcp_state hdcp_state;
|
enum hdcp_state hdcp_state;
|
||||||
enum hdcp_lib_wakeup_cmd wakeup_cmd;
|
enum hdcp_lib_wakeup_cmd wakeup_cmd;
|
||||||
bool repeater_flag;
|
bool repeater_flag;
|
||||||
|
bool tethered;
|
||||||
struct qseecom_handle *qseecom_handle;
|
struct qseecom_handle *qseecom_handle;
|
||||||
int last_msg_sent;
|
int last_msg_sent;
|
||||||
char *last_msg_recvd_buf;
|
char *last_msg_recvd_buf;
|
||||||
|
@ -353,13 +354,13 @@ struct hdcp_lib_handle {
|
||||||
struct completion topo_wait;
|
struct completion topo_wait;
|
||||||
|
|
||||||
struct kthread_worker worker;
|
struct kthread_worker worker;
|
||||||
struct kthread_work init;
|
struct kthread_work wk_init;
|
||||||
struct kthread_work msg_sent;
|
struct kthread_work wk_msg_sent;
|
||||||
struct kthread_work msg_recvd;
|
struct kthread_work wk_msg_recvd;
|
||||||
struct kthread_work timeout;
|
struct kthread_work wk_timeout;
|
||||||
struct kthread_work clean;
|
struct kthread_work wk_clean;
|
||||||
struct kthread_work topology;
|
struct kthread_work wk_topology;
|
||||||
struct kthread_work stream;
|
struct kthread_work wk_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hdcp_lib_message_map {
|
struct hdcp_lib_message_map {
|
||||||
|
@ -367,6 +368,13 @@ struct hdcp_lib_message_map {
|
||||||
const char *msg_name;
|
const char *msg_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void hdcp_lib_clean(struct hdcp_lib_handle *handle);
|
||||||
|
static void hdcp_lib_init(struct hdcp_lib_handle *handle);
|
||||||
|
static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle);
|
||||||
|
static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle);
|
||||||
|
static void hdcp_lib_timeout(struct hdcp_lib_handle *handle);
|
||||||
|
static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
|
||||||
|
|
||||||
static struct qseecom_handle *hdcp1_handle;
|
static struct qseecom_handle *hdcp1_handle;
|
||||||
static bool hdcp1_supported = true;
|
static bool hdcp1_supported = true;
|
||||||
|
|
||||||
|
@ -467,7 +475,7 @@ static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle)
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
if (!atomic_read(&handle->hdcp_off))
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
HDCP_LIB_EXECUTE(clean);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -678,21 +686,17 @@ exit:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_query_stream_type_work(struct kthread_work *work)
|
static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct hdcp_query_stream_type_req *req_buf;
|
struct hdcp_query_stream_type_req *req_buf;
|
||||||
struct hdcp_query_stream_type_rsp *rsp_buf;
|
struct hdcp_query_stream_type_rsp *rsp_buf;
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
|
||||||
struct hdcp_lib_handle, stream);
|
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
pr_err("invalid handle\n");
|
pr_err("invalid handle\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
/* send command to TZ */
|
/* send command to TZ */
|
||||||
req_buf = (struct hdcp_query_stream_type_req *)handle->
|
req_buf = (struct hdcp_query_stream_type_req *)handle->
|
||||||
qseecom_handle->sbuf;
|
qseecom_handle->sbuf;
|
||||||
|
@ -724,12 +728,18 @@ static void hdcp_lib_query_stream_type_work(struct kthread_work *work)
|
||||||
handle->hdcp_timeout = rsp_buf->timeout;
|
handle->hdcp_timeout = rsp_buf->timeout;
|
||||||
handle->msglen = rsp_buf->msglen;
|
handle->msglen = rsp_buf->msglen;
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
if (!rc && !atomic_read(&handle->hdcp_off))
|
if (!rc && !atomic_read(&handle->hdcp_off))
|
||||||
hdcp_lib_send_message(handle);
|
hdcp_lib_send_message(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_query_stream_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
|
struct hdcp_lib_handle, wk_stream);
|
||||||
|
|
||||||
|
hdcp_lib_stream(handle);
|
||||||
|
}
|
||||||
|
|
||||||
static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
|
static bool hdcp_lib_client_feature_supported(void *phdcpcontext)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -759,46 +769,46 @@ exit:
|
||||||
|
|
||||||
static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
|
static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
if (!list_empty(&handle->init.node))
|
if (!list_empty(&handle->wk_init.node))
|
||||||
pr_debug("init work queued\n");
|
pr_debug("init work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->init)
|
if (handle->worker.current_work == &handle->wk_init)
|
||||||
pr_debug("init work executing\n");
|
pr_debug("init work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->msg_sent.node))
|
if (!list_empty(&handle->wk_msg_sent.node))
|
||||||
pr_debug("msg_sent work queued\n");
|
pr_debug("msg_sent work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->msg_sent)
|
if (handle->worker.current_work == &handle->wk_msg_sent)
|
||||||
pr_debug("msg_sent work executing\n");
|
pr_debug("msg_sent work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->msg_recvd.node))
|
if (!list_empty(&handle->wk_msg_recvd.node))
|
||||||
pr_debug("msg_recvd work queued\n");
|
pr_debug("msg_recvd work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->msg_recvd)
|
if (handle->worker.current_work == &handle->wk_msg_recvd)
|
||||||
pr_debug("msg_recvd work executing\n");
|
pr_debug("msg_recvd work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->timeout.node))
|
if (!list_empty(&handle->wk_timeout.node))
|
||||||
pr_debug("timeout work queued\n");
|
pr_debug("timeout work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->timeout)
|
if (handle->worker.current_work == &handle->wk_timeout)
|
||||||
pr_debug("timeout work executing\n");
|
pr_debug("timeout work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->clean.node))
|
if (!list_empty(&handle->wk_clean.node))
|
||||||
pr_debug("clean work queued\n");
|
pr_debug("clean work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->clean)
|
if (handle->worker.current_work == &handle->wk_clean)
|
||||||
pr_debug("clean work executing\n");
|
pr_debug("clean work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->topology.node))
|
if (!list_empty(&handle->wk_topology.node))
|
||||||
pr_debug("topology work queued\n");
|
pr_debug("topology work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->topology)
|
if (handle->worker.current_work == &handle->wk_topology)
|
||||||
pr_debug("topology work executing\n");
|
pr_debug("topology work executing\n");
|
||||||
|
|
||||||
if (!list_empty(&handle->stream.node))
|
if (!list_empty(&handle->wk_stream.node))
|
||||||
pr_debug("stream work queued\n");
|
pr_debug("stream work queued\n");
|
||||||
|
|
||||||
if (handle->worker.current_work == &handle->stream)
|
if (handle->worker.current_work == &handle->wk_stream)
|
||||||
pr_debug("stream work executing\n");
|
pr_debug("stream work executing\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,6 +839,28 @@ exit:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_update_exec_type(void *ctx, bool tethered)
|
||||||
|
{
|
||||||
|
struct hdcp_lib_handle *handle = ctx;
|
||||||
|
|
||||||
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&handle->wakeup_mutex);
|
||||||
|
|
||||||
|
if (handle->tethered == tethered) {
|
||||||
|
pr_debug("exec mode same as %s\n",
|
||||||
|
tethered ? "tethered" : "threaded");
|
||||||
|
} else {
|
||||||
|
handle->tethered = tethered;
|
||||||
|
|
||||||
|
pr_debug("exec mode changed to %s\n",
|
||||||
|
tethered ? "tethered" : "threaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&handle->wakeup_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
|
static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
|
||||||
{
|
{
|
||||||
struct hdcp_lib_handle *handle;
|
struct hdcp_lib_handle *handle;
|
||||||
|
@ -846,9 +878,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
|
||||||
handle->wakeup_cmd = data->cmd;
|
handle->wakeup_cmd = data->cmd;
|
||||||
handle->timeout_left = data->timeout;
|
handle->timeout_left = data->timeout;
|
||||||
|
|
||||||
pr_debug("%s, timeout left: %dms\n",
|
pr_debug("%s, timeout left: %dms, tethered %d\n",
|
||||||
hdcp_lib_cmd_to_str(handle->wakeup_cmd),
|
hdcp_lib_cmd_to_str(handle->wakeup_cmd),
|
||||||
handle->timeout_left);
|
handle->timeout_left, handle->tethered);
|
||||||
|
|
||||||
rc = hdcp_lib_check_valid_state(handle);
|
rc = hdcp_lib_check_valid_state(handle);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -885,42 +917,42 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
|
||||||
atomic_set(&handle->hdcp_off, 0);
|
atomic_set(&handle->hdcp_off, 0);
|
||||||
handle->hdcp_state = HDCP_STATE_INIT;
|
handle->hdcp_state = HDCP_STATE_INIT;
|
||||||
|
|
||||||
queue_kthread_work(&handle->worker, &handle->init);
|
HDCP_LIB_EXECUTE(init);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_STOP:
|
case HDCP_LIB_WKUP_CMD_STOP:
|
||||||
atomic_set(&handle->hdcp_off, 1);
|
atomic_set(&handle->hdcp_off, 1);
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
|
||||||
|
HDCP_LIB_EXECUTE(clean);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
|
case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS:
|
||||||
handle->last_msg_sent = handle->listener_buf[0];
|
handle->last_msg_sent = handle->listener_buf[0];
|
||||||
|
|
||||||
queue_kthread_work(&handle->worker, &handle->msg_sent);
|
HDCP_LIB_EXECUTE(msg_sent);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
|
case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
|
||||||
case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
|
case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
HDCP_LIB_EXECUTE(clean);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
|
case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
|
||||||
queue_kthread_work(&handle->worker, &handle->msg_recvd);
|
HDCP_LIB_EXECUTE(msg_recvd);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
|
case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT:
|
||||||
queue_kthread_work(&handle->worker, &handle->timeout);
|
HDCP_LIB_EXECUTE(timeout);
|
||||||
break;
|
break;
|
||||||
case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
|
case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
|
||||||
queue_kthread_work(&handle->worker, &handle->stream);
|
HDCP_LIB_EXECUTE(stream);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
|
pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
|
||||||
}
|
}
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&handle->wakeup_mutex);
|
mutex_unlock(&handle->wakeup_mutex);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_msg_sent_work(struct kthread_work *work)
|
static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
|
||||||
struct hdcp_lib_handle, msg_sent);
|
|
||||||
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
|
@ -928,13 +960,6 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
|
|
||||||
pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
cdata.context = handle->client_ctx;
|
cdata.context = handle->client_ctx;
|
||||||
|
|
||||||
switch (handle->last_msg_sent) {
|
switch (handle->last_msg_sent) {
|
||||||
|
@ -942,15 +967,15 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)
|
||||||
if (handle->repeater_flag) {
|
if (handle->repeater_flag) {
|
||||||
if (!atomic_read(&handle->hdcp_off))
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
queue_kthread_work(&handle->worker,
|
queue_kthread_work(&handle->worker,
|
||||||
&handle->topology);
|
&handle->wk_topology);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hdcp_lib_enable_encryption(handle))
|
if (!hdcp_lib_enable_encryption(handle)) {
|
||||||
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
|
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
|
||||||
else
|
} else {
|
||||||
if (!atomic_read(&handle->hdcp_off))
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
queue_kthread_work(&handle->worker,
|
HDCP_LIB_EXECUTE(clean);
|
||||||
&handle->clean);
|
}
|
||||||
break;
|
break;
|
||||||
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
|
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
|
||||||
pr_debug("Repeater authentication successful\n");
|
pr_debug("Repeater authentication successful\n");
|
||||||
|
@ -960,72 +985,70 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work)
|
||||||
cdata.timeout = handle->timeout_left;
|
cdata.timeout = handle->timeout_left;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
hdcp_lib_wakeup_client(handle, &cdata);
|
hdcp_lib_wakeup_client(handle, &cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_msg_sent_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
|
struct hdcp_lib_handle, wk_msg_sent);
|
||||||
|
|
||||||
|
if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) {
|
||||||
|
pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdcp_lib_msg_sent(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_init(struct hdcp_lib_handle *handle)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!handle) {
|
||||||
|
pr_err("invalid handle\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) {
|
||||||
|
pr_err("invalid wakeup command %d\n", handle->wakeup_cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = hdcp_lib_library_load(handle);
|
||||||
|
if (rc)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
rc = hdcp_lib_txmtr_init(handle);
|
||||||
|
if (rc)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
hdcp_lib_send_message(handle);
|
||||||
|
|
||||||
|
return;
|
||||||
|
exit:
|
||||||
|
HDCP_LIB_EXECUTE(clean);
|
||||||
|
}
|
||||||
|
|
||||||
static void hdcp_lib_init_work(struct kthread_work *work)
|
static void hdcp_lib_init_work(struct kthread_work *work)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
bool send_msg = false;
|
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
struct hdcp_lib_handle, init);
|
struct hdcp_lib_handle, wk_init);
|
||||||
|
|
||||||
if (!handle) {
|
hdcp_lib_init(handle);
|
||||||
pr_err("invalid handle\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
|
|
||||||
rc = hdcp_lib_library_load(handle);
|
|
||||||
if (rc)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
rc = hdcp_lib_txmtr_init(handle);
|
|
||||||
if (rc)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
send_msg = true;
|
|
||||||
} else if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_STOP) {
|
|
||||||
rc = hdcp_lib_txmtr_deinit(handle);
|
|
||||||
if (rc)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
rc = hdcp_lib_library_unload(handle);
|
|
||||||
if (rc)
|
|
||||||
goto exit;
|
|
||||||
} else {
|
|
||||||
pr_err("invalid wakeup cmd: %d\n", handle->wakeup_cmd);
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
if (send_msg)
|
|
||||||
hdcp_lib_send_message(handle);
|
|
||||||
|
|
||||||
if (rc && !atomic_read(&handle->hdcp_off))
|
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
|
static void hdcp_lib_timeout(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
bool send_msg = false;
|
|
||||||
struct hdcp_send_timeout_req *req_buf;
|
struct hdcp_send_timeout_req *req_buf;
|
||||||
struct hdcp_send_timeout_rsp *rsp_buf;
|
struct hdcp_send_timeout_rsp *rsp_buf;
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
|
||||||
struct hdcp_lib_handle, timeout);
|
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
pr_err("invalid handle\n");
|
pr_err("invalid handle\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
req_buf = (struct hdcp_send_timeout_req *)
|
req_buf = (struct hdcp_send_timeout_req *)
|
||||||
(handle->qseecom_handle->sbuf);
|
(handle->qseecom_handle->sbuf);
|
||||||
req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
|
req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT;
|
||||||
|
@ -1068,23 +1091,24 @@ static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
|
||||||
handle->hdcp_timeout = rsp_buf->timeout;
|
handle->hdcp_timeout = rsp_buf->timeout;
|
||||||
handle->msglen = rsp_buf->msglen;
|
handle->msglen = rsp_buf->msglen;
|
||||||
|
|
||||||
send_msg = true;
|
hdcp_lib_send_message(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
|
HDCP_LIB_EXECUTE(clean);
|
||||||
if (send_msg)
|
|
||||||
hdcp_lib_send_message(handle);
|
|
||||||
|
|
||||||
if (rc && !atomic_read(&handle->hdcp_off))
|
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_cleanup_work(struct kthread_work *work)
|
static void hdcp_lib_manage_timeout_work(struct kthread_work *work)
|
||||||
{
|
{
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
struct hdcp_lib_handle, clean);
|
struct hdcp_lib_handle, wk_timeout);
|
||||||
|
|
||||||
|
hdcp_lib_timeout(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
|
||||||
|
{
|
||||||
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
|
@ -1092,15 +1116,11 @@ static void hdcp_lib_cleanup_work(struct kthread_work *work)
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
cdata.context = handle->client_ctx;
|
|
||||||
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED;
|
|
||||||
|
|
||||||
hdcp_lib_txmtr_deinit(handle);
|
hdcp_lib_txmtr_deinit(handle);
|
||||||
hdcp_lib_library_unload(handle);
|
hdcp_lib_library_unload(handle);
|
||||||
|
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
cdata.context = handle->client_ctx;
|
||||||
|
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED;
|
||||||
|
|
||||||
if (!atomic_read(&handle->hdcp_off))
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
hdcp_lib_wakeup_client(handle, &cdata);
|
hdcp_lib_wakeup_client(handle, &cdata);
|
||||||
|
@ -1108,23 +1128,29 @@ static void hdcp_lib_cleanup_work(struct kthread_work *work)
|
||||||
atomic_set(&handle->hdcp_off, 1);
|
atomic_set(&handle->hdcp_off, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
|
|
||||||
|
static void hdcp_lib_cleanup_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
|
struct hdcp_lib_handle, wk_clean);
|
||||||
|
|
||||||
|
hdcp_lib_clean(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
||||||
struct hdcp_rcvd_msg_req *req_buf;
|
struct hdcp_rcvd_msg_req *req_buf;
|
||||||
struct hdcp_rcvd_msg_rsp *rsp_buf;
|
struct hdcp_rcvd_msg_rsp *rsp_buf;
|
||||||
uint32_t msglen;
|
uint32_t msglen;
|
||||||
char *msg = NULL;
|
char *msg;
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
|
||||||
struct hdcp_lib_handle, msg_recvd);
|
|
||||||
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};
|
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
pr_err("invalid handle\n");
|
pr_err("invalid handle\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&handle->hdcp_lock);
|
|
||||||
cdata.context = handle->client_ctx;
|
cdata.context = handle->client_ctx;
|
||||||
|
|
||||||
mutex_lock(&handle->msg_lock);
|
mutex_lock(&handle->msg_lock);
|
||||||
|
@ -1233,19 +1259,26 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
kzfree(msg);
|
kzfree(msg);
|
||||||
mutex_unlock(&handle->hdcp_lock);
|
|
||||||
|
|
||||||
hdcp_lib_wakeup_client(handle, &cdata);
|
hdcp_lib_wakeup_client(handle, &cdata);
|
||||||
|
|
||||||
if (rc && !atomic_read(&handle->hdcp_off))
|
if (rc && !atomic_read(&handle->hdcp_off))
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
HDCP_LIB_EXECUTE(clean);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
|
struct hdcp_lib_handle, wk_msg_recvd);
|
||||||
|
|
||||||
|
hdcp_lib_msg_recvd(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdcp_lib_topology_work(struct kthread_work *work)
|
static void hdcp_lib_topology_work(struct kthread_work *work)
|
||||||
{
|
{
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
struct hdcp_lib_handle *handle = container_of(work,
|
struct hdcp_lib_handle *handle = container_of(work,
|
||||||
struct hdcp_lib_handle, topology);
|
struct hdcp_lib_handle, wk_topology);
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
pr_err("invalid input\n");
|
pr_err("invalid input\n");
|
||||||
|
@ -1258,7 +1291,7 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
|
||||||
pr_err("topology receiver id list timeout\n");
|
pr_err("topology receiver id list timeout\n");
|
||||||
|
|
||||||
if (!atomic_read(&handle->hdcp_off))
|
if (!atomic_read(&handle->hdcp_off))
|
||||||
queue_kthread_work(&handle->worker, &handle->clean);
|
HDCP_LIB_EXECUTE(clean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,32 +1362,35 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hdcp_library_register(void **pphdcpcontext,
|
int hdcp_library_register(struct hdcp_register_data *data)
|
||||||
struct hdcp_client_ops *client_ops,
|
|
||||||
struct hdcp_txmtr_ops *txmtr_ops,
|
|
||||||
void *client_ctx)
|
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct hdcp_lib_handle *handle = NULL;
|
struct hdcp_lib_handle *handle = NULL;
|
||||||
|
|
||||||
if (!pphdcpcontext) {
|
if (!data) {
|
||||||
pr_err("invalid input: context passed\n");
|
pr_err("invalid input\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!txmtr_ops) {
|
if (!data->txmtr_ops) {
|
||||||
pr_err("invalid input: txmtr context\n");
|
pr_err("invalid input: txmtr context\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!client_ops) {
|
if (!data->client_ops) {
|
||||||
pr_err("invalid input: client_ops\n");
|
pr_err("invalid input: client_ops\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->hdcp_ctx) {
|
||||||
|
pr_err("invalid input: hdcp_ctx\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* populate ops to be called by client */
|
/* populate ops to be called by client */
|
||||||
txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
|
data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
|
||||||
txmtr_ops->wakeup = hdcp_lib_wakeup;
|
data->txmtr_ops->wakeup = hdcp_lib_wakeup;
|
||||||
|
data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type;
|
||||||
|
|
||||||
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
|
@ -1362,24 +1398,26 @@ int hdcp_library_register(void **pphdcpcontext,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->client_ctx = client_ctx;
|
handle->client_ctx = data->client_ctx;
|
||||||
handle->client_ops = client_ops;
|
handle->client_ops = data->client_ops;
|
||||||
|
handle->tethered = data->tethered;
|
||||||
|
|
||||||
|
pr_debug("tethered %d\n", handle->tethered);
|
||||||
|
|
||||||
atomic_set(&handle->hdcp_off, 0);
|
atomic_set(&handle->hdcp_off, 0);
|
||||||
|
|
||||||
mutex_init(&handle->hdcp_lock);
|
|
||||||
mutex_init(&handle->msg_lock);
|
mutex_init(&handle->msg_lock);
|
||||||
mutex_init(&handle->wakeup_mutex);
|
mutex_init(&handle->wakeup_mutex);
|
||||||
|
|
||||||
init_kthread_worker(&handle->worker);
|
init_kthread_worker(&handle->worker);
|
||||||
|
|
||||||
init_kthread_work(&handle->init, hdcp_lib_init_work);
|
init_kthread_work(&handle->wk_init, hdcp_lib_init_work);
|
||||||
init_kthread_work(&handle->msg_sent, hdcp_lib_msg_sent_work);
|
init_kthread_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work);
|
||||||
init_kthread_work(&handle->msg_recvd, hdcp_lib_msg_recvd_work);
|
init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
|
||||||
init_kthread_work(&handle->timeout, hdcp_lib_manage_timeout_work);
|
init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
|
||||||
init_kthread_work(&handle->clean, hdcp_lib_cleanup_work);
|
init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work);
|
||||||
init_kthread_work(&handle->topology, hdcp_lib_topology_work);
|
init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work);
|
||||||
init_kthread_work(&handle->stream, hdcp_lib_query_stream_type_work);
|
init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work);
|
||||||
|
|
||||||
init_completion(&handle->topo_wait);
|
init_completion(&handle->topo_wait);
|
||||||
|
|
||||||
|
@ -1389,7 +1427,7 @@ int hdcp_library_register(void **pphdcpcontext,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
*((struct hdcp_lib_handle **)pphdcpcontext) = handle;
|
*data->hdcp_ctx = handle;
|
||||||
|
|
||||||
handle->thread = kthread_run(kthread_worker_fn,
|
handle->thread = kthread_run(kthread_worker_fn,
|
||||||
&handle->worker, "hdcp_tz_lib");
|
&handle->worker, "hdcp_tz_lib");
|
||||||
|
@ -1423,7 +1461,6 @@ void hdcp_library_deregister(void *phdcpcontext)
|
||||||
kzfree(handle->qseecom_handle);
|
kzfree(handle->qseecom_handle);
|
||||||
kzfree(handle->last_msg_recvd_buf);
|
kzfree(handle->last_msg_recvd_buf);
|
||||||
|
|
||||||
mutex_destroy(&handle->hdcp_lock);
|
|
||||||
mutex_destroy(&handle->wakeup_mutex);
|
mutex_destroy(&handle->wakeup_mutex);
|
||||||
|
|
||||||
kzfree(handle->listener_buf);
|
kzfree(handle->listener_buf);
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct hdmi_hdcp_init_data {
|
||||||
u32 phy_addr;
|
u32 phy_addr;
|
||||||
u32 hdmi_tx_ver;
|
u32 hdmi_tx_ver;
|
||||||
struct msm_hdmi_mode_timing_info *timing;
|
struct msm_hdmi_mode_timing_info *timing;
|
||||||
|
bool tethered;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hdmi_hdcp_ops {
|
struct hdmi_hdcp_ops {
|
||||||
|
|
|
@ -51,6 +51,7 @@ enum hdmi_hdcp2p2_sink_status {
|
||||||
|
|
||||||
struct hdmi_hdcp2p2_ctrl {
|
struct hdmi_hdcp2p2_ctrl {
|
||||||
atomic_t auth_state;
|
atomic_t auth_state;
|
||||||
|
bool tethered;
|
||||||
enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */
|
enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */
|
||||||
struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */
|
struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */
|
||||||
struct mutex mutex; /* mutex to protect access to ctrl */
|
struct mutex mutex; /* mutex to protect access to ctrl */
|
||||||
|
@ -77,6 +78,11 @@ struct hdmi_hdcp2p2_ctrl {
|
||||||
struct delayed_work link_check_work;
|
struct delayed_work link_check_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hdmi_hdcp2p2_auth(struct hdmi_hdcp2p2_ctrl *ctrl);
|
||||||
|
static void hdmi_hdcp2p2_send_msg(struct hdmi_hdcp2p2_ctrl *ctrl);
|
||||||
|
static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl);
|
||||||
|
static void hdmi_hdcp2p2_auth_status(struct hdmi_hdcp2p2_ctrl *ctrl);
|
||||||
|
|
||||||
static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl)
|
static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
|
if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
|
||||||
|
@ -133,9 +139,9 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
|
||||||
|
|
||||||
mutex_lock(&ctrl->wakeup_mutex);
|
mutex_lock(&ctrl->wakeup_mutex);
|
||||||
|
|
||||||
pr_debug("cmd: %s, timeout %dms\n",
|
pr_debug("cmd: %s, timeout %dms, tethered %d\n",
|
||||||
hdmi_hdcp_cmd_to_str(data->cmd),
|
hdmi_hdcp_cmd_to_str(data->cmd),
|
||||||
data->timeout);
|
data->timeout, ctrl->tethered);
|
||||||
|
|
||||||
ctrl->wakeup_cmd = data->cmd;
|
ctrl->wakeup_cmd = data->cmd;
|
||||||
|
|
||||||
|
@ -152,6 +158,9 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
|
||||||
if (hdmi_hdcp2p2_copy_buf(ctrl, data))
|
if (hdmi_hdcp2p2_copy_buf(ctrl, data))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
if (ctrl->tethered)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
switch (ctrl->wakeup_cmd) {
|
switch (ctrl->wakeup_cmd) {
|
||||||
case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
|
case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
|
||||||
queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
|
queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
|
||||||
|
@ -179,6 +188,9 @@ static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
if (ctrl)
|
||||||
|
ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
|
||||||
|
|
||||||
if (ctrl && ctrl->lib && ctrl->lib->wakeup &&
|
if (ctrl && ctrl->lib && ctrl->lib->wakeup &&
|
||||||
data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) {
|
data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) {
|
||||||
rc = ctrl->lib->wakeup(data);
|
rc = ctrl->lib->wakeup(data);
|
||||||
|
@ -190,6 +202,55 @@ static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdmi_hdcp2p2_run(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
if (!ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
switch (ctrl->wakeup_cmd) {
|
||||||
|
case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
|
||||||
|
hdmi_hdcp2p2_send_msg(ctrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
|
||||||
|
hdmi_hdcp2p2_recv_msg(ctrl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
|
||||||
|
case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
|
||||||
|
hdmi_hdcp2p2_auth_status(ctrl);
|
||||||
|
default:
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hdmi_hdcp2p2_authenticate_tethered(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = hdmi_hdcp2p2_auth(ctrl);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("auth failed %d\n", rc);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdmi_hdcp2p2_run(ctrl);
|
||||||
|
exit:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl)
|
static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
|
@ -217,17 +278,27 @@ static void hdmi_hdcp2p2_off(void *input)
|
||||||
|
|
||||||
hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
|
hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
|
||||||
|
|
||||||
cdata.context = input;
|
if (ctrl->tethered) {
|
||||||
|
hdmi_hdcp2p2_auth(ctrl);
|
||||||
hdmi_hdcp2p2_wakeup(&cdata);
|
} else {
|
||||||
|
cdata.context = input;
|
||||||
|
hdmi_hdcp2p2_wakeup(&cdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdmi_hdcp2p2_authenticate(void *input)
|
static int hdmi_hdcp2p2_authenticate(void *input)
|
||||||
{
|
{
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = input;
|
struct hdmi_hdcp2p2_ctrl *ctrl = input;
|
||||||
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
|
struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
|
||||||
|
u32 regval;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Enable authentication success interrupt */
|
||||||
|
regval = DSS_REG_R(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2);
|
||||||
|
regval |= BIT(1) | BIT(2);
|
||||||
|
|
||||||
|
DSS_REG_W(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2, regval);
|
||||||
|
|
||||||
flush_kthread_worker(&ctrl->worker);
|
flush_kthread_worker(&ctrl->worker);
|
||||||
|
|
||||||
ctrl->sink_status = SINK_CONNECTED;
|
ctrl->sink_status = SINK_CONNECTED;
|
||||||
|
@ -237,15 +308,18 @@ static int hdmi_hdcp2p2_authenticate(void *input)
|
||||||
hdmi_scrambler_ddc_disable(ctrl->init_data.ddc_ctrl);
|
hdmi_scrambler_ddc_disable(ctrl->init_data.ddc_ctrl);
|
||||||
hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
|
hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
|
||||||
|
|
||||||
cdata.context = input;
|
if (ctrl->tethered) {
|
||||||
hdmi_hdcp2p2_wakeup(&cdata);
|
hdmi_hdcp2p2_authenticate_tethered(ctrl);
|
||||||
|
} else {
|
||||||
|
cdata.context = input;
|
||||||
|
hdmi_hdcp2p2_wakeup(&cdata);
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdmi_hdcp2p2_reauthenticate(void *input)
|
static int hdmi_hdcp2p2_reauthenticate(void *input)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
|
struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
|
@ -255,11 +329,8 @@ static int hdmi_hdcp2p2_reauthenticate(void *input)
|
||||||
|
|
||||||
hdmi_hdcp2p2_reset((struct hdmi_hdcp2p2_ctrl *)input);
|
hdmi_hdcp2p2_reset((struct hdmi_hdcp2p2_ctrl *)input);
|
||||||
|
|
||||||
rc = hdmi_hdcp2p2_authenticate(input);
|
return hdmi_hdcp2p2_authenticate(input);
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t hdmi_hdcp2p2_sysfs_rda_sink_status(struct device *dev,
|
static ssize_t hdmi_hdcp2p2_sysfs_rda_sink_status(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -281,6 +352,54 @@ static ssize_t hdmi_hdcp2p2_sysfs_rda_sink_status(struct device *dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t hdmi_hdcp2p2_sysfs_rda_tethered(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl =
|
||||||
|
hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2);
|
||||||
|
|
||||||
|
if (!ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->mutex);
|
||||||
|
ret = snprintf(buf, PAGE_SIZE, "%d\n", ctrl->tethered);
|
||||||
|
mutex_unlock(&ctrl->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t hdmi_hdcp2p2_sysfs_wta_tethered(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl =
|
||||||
|
hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2);
|
||||||
|
int rc, tethered;
|
||||||
|
|
||||||
|
if (!ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->mutex);
|
||||||
|
rc = kstrtoint(buf, 10, &tethered);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("kstrtoint failed. rc=%d\n", rc);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl->tethered = !!tethered;
|
||||||
|
|
||||||
|
if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx)
|
||||||
|
ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered);
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&ctrl->mutex);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t hdmi_hdcp2p2_sysfs_rda_trigger(struct device *dev,
|
static ssize_t hdmi_hdcp2p2_sysfs_rda_trigger(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -366,6 +485,9 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||||
|
|
||||||
|
if (ctrl->tethered)
|
||||||
|
hdmi_hdcp2p2_run(ctrl);
|
||||||
|
|
||||||
if (enc_notify && ctrl->init_data.notify_status)
|
if (enc_notify && ctrl->init_data.notify_status)
|
||||||
ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
|
ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
|
||||||
|
|
||||||
|
@ -424,7 +546,7 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl,
|
int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl,
|
||||||
u8 *buf, size_t size)
|
u8 *buf, size_t size)
|
||||||
{
|
{
|
||||||
struct hdmi_tx_ddc_data ddc_data;
|
struct hdmi_tx_ddc_data ddc_data;
|
||||||
|
@ -503,12 +625,15 @@ static DEVICE_ATTR(sink_status, S_IRUGO, hdmi_hdcp2p2_sysfs_rda_sink_status,
|
||||||
NULL);
|
NULL);
|
||||||
static DEVICE_ATTR(hdcp2_version, S_IRUGO, hdmi_hdcp2p2_sysfs_rda_hdcp2_version,
|
static DEVICE_ATTR(hdcp2_version, S_IRUGO, hdmi_hdcp2p2_sysfs_rda_hdcp2_version,
|
||||||
NULL);
|
NULL);
|
||||||
|
static DEVICE_ATTR(tethered, S_IRUGO | S_IWUSR, hdmi_hdcp2p2_sysfs_rda_tethered,
|
||||||
|
hdmi_hdcp2p2_sysfs_wta_tethered);
|
||||||
|
|
||||||
static struct attribute *hdmi_hdcp2p2_fs_attrs[] = {
|
static struct attribute *hdmi_hdcp2p2_fs_attrs[] = {
|
||||||
&dev_attr_trigger.attr,
|
&dev_attr_trigger.attr,
|
||||||
&dev_attr_min_level_change.attr,
|
&dev_attr_min_level_change.attr,
|
||||||
&dev_attr_sink_status.attr,
|
&dev_attr_sink_status.attr,
|
||||||
&dev_attr_hdcp2_version.attr,
|
&dev_attr_hdcp2_version.attr,
|
||||||
|
&dev_attr_tethered.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,22 +666,19 @@ end:
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
|
static void hdmi_hdcp2p2_send_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
|
||||||
struct hdmi_hdcp2p2_ctrl, send_msg);
|
|
||||||
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
||||||
char *msg;
|
|
||||||
uint32_t msglen;
|
uint32_t msglen;
|
||||||
|
char *msg = NULL;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
pr_err("invalid input\n");
|
pr_err("invalid input\n");
|
||||||
return;
|
rc = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ctrl->mutex);
|
|
||||||
|
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
|
|
||||||
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
||||||
|
@ -569,12 +691,14 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
|
||||||
|
|
||||||
if (!msglen) {
|
if (!msglen) {
|
||||||
mutex_unlock(&ctrl->msg_lock);
|
mutex_unlock(&ctrl->msg_lock);
|
||||||
|
rc = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = kzalloc(msglen, GFP_KERNEL);
|
msg = kzalloc(msglen, GFP_KERNEL);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
mutex_unlock(&ctrl->msg_lock);
|
mutex_unlock(&ctrl->msg_lock);
|
||||||
|
rc = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,41 +715,46 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
|
||||||
cdata.timeout = ctrl->timeout_left;
|
cdata.timeout = ctrl->timeout_left;
|
||||||
}
|
}
|
||||||
exit:
|
exit:
|
||||||
kzfree(msg);
|
kfree(msg);
|
||||||
mutex_unlock(&ctrl->mutex);
|
|
||||||
|
|
||||||
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
|
static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
int timeout_hsync;
|
|
||||||
char *recvd_msg_buf = NULL;
|
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
||||||
struct hdmi_hdcp2p2_ctrl, recv_msg);
|
struct hdmi_hdcp2p2_ctrl, send_msg);
|
||||||
|
|
||||||
|
hdmi_hdcp2p2_send_msg(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
int rc, timeout_hsync;
|
||||||
|
char *recvd_msg_buf = NULL;
|
||||||
struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
|
struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
|
||||||
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
|
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
|
||||||
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
pr_err("invalid input\n");
|
pr_err("invalid input\n");
|
||||||
return;
|
rc = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ctrl->mutex);
|
|
||||||
|
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
|
|
||||||
|
ddc_ctrl = ctrl->init_data.ddc_ctrl;
|
||||||
|
if (!ddc_ctrl) {
|
||||||
|
pr_err("invalid ddc ctrl\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
||||||
pr_err("hdcp is off\n");
|
pr_err("hdcp is off\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ddc_ctrl = ctrl->init_data.ddc_ctrl;
|
|
||||||
if (!ddc_ctrl)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
hdmi_ddc_config(ddc_ctrl);
|
hdmi_ddc_config(ddc_ctrl);
|
||||||
|
|
||||||
ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;
|
ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;
|
||||||
|
@ -667,13 +796,17 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL);
|
recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL);
|
||||||
if (!recvd_msg_buf)
|
if (!recvd_msg_buf) {
|
||||||
|
rc = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf,
|
rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf,
|
||||||
ddc_data->message_size, ctrl->timeout_left);
|
ddc_data->message_size, ctrl->timeout_left);
|
||||||
if (rc)
|
if (rc) {
|
||||||
pr_err("error reading message %d\n", rc);
|
pr_err("error reading message %d\n", rc);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
|
cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
|
||||||
cdata.recvd_msg_buf = recvd_msg_buf;
|
cdata.recvd_msg_buf = recvd_msg_buf;
|
||||||
|
@ -685,12 +818,19 @@ exit:
|
||||||
else if (rc)
|
else if (rc)
|
||||||
cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
|
cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED;
|
||||||
|
|
||||||
mutex_unlock(&ctrl->mutex);
|
|
||||||
|
|
||||||
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||||
kfree(recvd_msg_buf);
|
kfree(recvd_msg_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
||||||
|
struct hdmi_hdcp2p2_ctrl, recv_msg);
|
||||||
|
|
||||||
|
hdmi_hdcp2p2_recv_msg(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl)
|
static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
|
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
|
||||||
|
@ -726,48 +866,38 @@ static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false);
|
return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
|
static void hdmi_hdcp2p2_auth_status(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
|
||||||
struct hdmi_hdcp2p2_ctrl, status);
|
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
pr_err("invalid input\n");
|
pr_err("invalid input\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ctrl->mutex);
|
|
||||||
|
|
||||||
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
|
||||||
pr_err("hdcp is off\n");
|
pr_err("hdcp is off\n");
|
||||||
goto exit;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED) {
|
if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED) {
|
||||||
hdmi_hdcp2p2_auth_failed(ctrl);
|
hdmi_hdcp2p2_auth_failed(ctrl);
|
||||||
} else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS) {
|
} else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS) {
|
||||||
/* Enable interrupts */
|
|
||||||
u32 regval = DSS_REG_R(ctrl->init_data.core_io,
|
|
||||||
HDMI_HDCP_INT_CTRL2);
|
|
||||||
pr_debug("Now authenticated. Enabling interrupts\n");
|
|
||||||
regval |= BIT(1);
|
|
||||||
regval |= BIT(2);
|
|
||||||
regval |= BIT(5);
|
|
||||||
|
|
||||||
DSS_REG_W(ctrl->init_data.core_io,
|
|
||||||
HDMI_HDCP_INT_CTRL2, regval);
|
|
||||||
|
|
||||||
ctrl->init_data.notify_status(ctrl->init_data.cb_data,
|
ctrl->init_data.notify_status(ctrl->init_data.cb_data,
|
||||||
HDCP_STATE_AUTHENTICATED);
|
HDCP_STATE_AUTHENTICATED);
|
||||||
|
|
||||||
if (!hdmi_hdcp2p2_link_check(ctrl))
|
if (!hdmi_hdcp2p2_link_check(ctrl))
|
||||||
schedule_delayed_work(&ctrl->link_check_work,
|
queue_kthread_work(&ctrl->worker, &ctrl->link);
|
||||||
msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
|
|
||||||
}
|
}
|
||||||
exit:
|
|
||||||
mutex_unlock(&ctrl->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
||||||
|
struct hdmi_hdcp2p2_ctrl, status);
|
||||||
|
|
||||||
|
hdmi_hdcp2p2_auth_status(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_link_schedule_work(struct work_struct *work)
|
static void hdmi_hdcp2p2_link_schedule_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(to_delayed_work(work),
|
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(to_delayed_work(work),
|
||||||
|
@ -792,8 +922,6 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ctrl->mutex);
|
|
||||||
|
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
|
|
||||||
ddc_ctrl = ctrl->init_data.ddc_ctrl;
|
ddc_ctrl = ctrl->init_data.ddc_ctrl;
|
||||||
|
@ -842,15 +970,14 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&ctrl->mutex);
|
|
||||||
|
|
||||||
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||||
kfree(recvd_msg_buf);
|
kfree(recvd_msg_buf);
|
||||||
|
|
||||||
if (rc) {
|
if (ctrl->tethered)
|
||||||
/* notify hdmi tx about auth failure */
|
hdmi_hdcp2p2_run(ctrl);
|
||||||
hdmi_hdcp2p2_auth_failed(ctrl);
|
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
hdmi_hdcp2p2_auth_failed(ctrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,19 +986,16 @@ exit:
|
||||||
msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
|
msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)
|
static int hdmi_hdcp2p2_auth(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
|
||||||
struct hdmi_hdcp2p2_ctrl, auth);
|
|
||||||
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
pr_err("invalid input\n");
|
pr_err("invalid input\n");
|
||||||
return;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ctrl->mutex);
|
|
||||||
|
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
|
|
||||||
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
|
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
|
||||||
|
@ -879,10 +1003,19 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)
|
||||||
else
|
else
|
||||||
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
|
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
|
||||||
|
|
||||||
mutex_unlock(&ctrl->mutex);
|
rc = hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||||
|
if (rc)
|
||||||
if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata))
|
|
||||||
hdmi_hdcp2p2_auth_failed(ctrl);
|
hdmi_hdcp2p2_auth_failed(ctrl);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)
|
||||||
|
{
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
|
||||||
|
struct hdmi_hdcp2p2_ctrl, auth);
|
||||||
|
|
||||||
|
hdmi_hdcp2p2_auth(ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hdmi_hdcp2p2_deinit(void *input)
|
void hdmi_hdcp2p2_deinit(void *input)
|
||||||
|
@ -912,8 +1045,8 @@ void hdmi_hdcp2p2_deinit(void *input)
|
||||||
|
|
||||||
void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
|
void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
|
||||||
{
|
{
|
||||||
struct hdmi_hdcp2p2_ctrl *ctrl;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
struct hdmi_hdcp2p2_ctrl *ctrl;
|
||||||
static struct hdmi_hdcp_ops ops = {
|
static struct hdmi_hdcp_ops ops = {
|
||||||
.hdmi_hdcp_reauthenticate = hdmi_hdcp2p2_reauthenticate,
|
.hdmi_hdcp_reauthenticate = hdmi_hdcp2p2_reauthenticate,
|
||||||
.hdmi_hdcp_authenticate = hdmi_hdcp2p2_authenticate,
|
.hdmi_hdcp_authenticate = hdmi_hdcp2p2_authenticate,
|
||||||
|
@ -926,6 +1059,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hdcp_txmtr_ops txmtr_ops;
|
static struct hdcp_txmtr_ops txmtr_ops;
|
||||||
|
struct hdcp_register_data register_data;
|
||||||
|
|
||||||
pr_debug("HDCP2P2 feature initialization\n");
|
pr_debug("HDCP2P2 feature initialization\n");
|
||||||
|
|
||||||
|
@ -947,6 +1081,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
|
||||||
|
|
||||||
ctrl->init_data = *init_data;
|
ctrl->init_data = *init_data;
|
||||||
ctrl->lib = &txmtr_ops;
|
ctrl->lib = &txmtr_ops;
|
||||||
|
ctrl->tethered = init_data->tethered;
|
||||||
|
|
||||||
rc = sysfs_create_group(init_data->sysfs_kobj,
|
rc = sysfs_create_group(init_data->sysfs_kobj,
|
||||||
&hdmi_hdcp2p2_fs_attr_group);
|
&hdmi_hdcp2p2_fs_attr_group);
|
||||||
|
@ -964,8 +1099,13 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
|
||||||
mutex_init(&ctrl->msg_lock);
|
mutex_init(&ctrl->msg_lock);
|
||||||
mutex_init(&ctrl->wakeup_mutex);
|
mutex_init(&ctrl->wakeup_mutex);
|
||||||
|
|
||||||
rc = hdcp_library_register(&ctrl->lib_ctx,
|
register_data.hdcp_ctx = &ctrl->lib_ctx;
|
||||||
&client_ops, ctrl->lib, ctrl);
|
register_data.client_ops = &client_ops;
|
||||||
|
register_data.txmtr_ops = &txmtr_ops;
|
||||||
|
register_data.client_ctx = ctrl;
|
||||||
|
register_data.tethered = ctrl->tethered;
|
||||||
|
|
||||||
|
rc = hdcp_library_register(®ister_data);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("Unable to register with HDCP 2.2 library\n");
|
pr_err("Unable to register with HDCP 2.2 library\n");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -1563,9 +1563,9 @@ end:
|
||||||
static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||||
struct fb_info *fbi)
|
struct fb_info *fbi)
|
||||||
{
|
{
|
||||||
struct hdmi_edid_init_data edid_init_data;
|
struct hdmi_edid_init_data edid_init_data = {0};
|
||||||
struct hdmi_hdcp_init_data hdcp_init_data;
|
struct hdmi_hdcp_init_data hdcp_init_data = {0};
|
||||||
struct hdmi_cec_init_data cec_init_data;
|
struct hdmi_cec_init_data cec_init_data = {0};
|
||||||
struct resource *res = NULL;
|
struct resource *res = NULL;
|
||||||
void *fd = NULL;
|
void *fd = NULL;
|
||||||
|
|
||||||
|
@ -4332,6 +4332,8 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
|
||||||
|
|
||||||
case MDSS_EVENT_BLANK:
|
case MDSS_EVENT_BLANK:
|
||||||
if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) {
|
if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) {
|
||||||
|
flush_delayed_work(&hdmi_ctrl->hdcp_cb_work);
|
||||||
|
|
||||||
DEV_DBG("%s: Turning off HDCP\n", __func__);
|
DEV_DBG("%s: Turning off HDCP\n", __func__);
|
||||||
hdmi_ctrl->hdcp_ops->hdmi_hdcp_off(
|
hdmi_ctrl->hdcp_ops->hdmi_hdcp_off(
|
||||||
hdmi_ctrl->hdcp_data);
|
hdmi_ctrl->hdcp_data);
|
||||||
|
|
|
@ -96,7 +96,7 @@ static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
|
||||||
struct hdcp_txmtr_ops {
|
struct hdcp_txmtr_ops {
|
||||||
int (*wakeup)(struct hdcp_lib_wakeup_data *data);
|
int (*wakeup)(struct hdcp_lib_wakeup_data *data);
|
||||||
bool (*feature_supported)(void *phdcpcontext);
|
bool (*feature_supported)(void *phdcpcontext);
|
||||||
|
void (*update_exec_type)(void *ctx, bool tethered);
|
||||||
int (*hdcp_txmtr_get_state)(void *phdcpcontext,
|
int (*hdcp_txmtr_get_state)(void *phdcpcontext,
|
||||||
uint32_t *state);
|
uint32_t *state);
|
||||||
};
|
};
|
||||||
|
@ -105,9 +105,15 @@ struct hdcp_client_ops {
|
||||||
int (*wakeup)(struct hdmi_hdcp_wakeup_data *data);
|
int (*wakeup)(struct hdmi_hdcp_wakeup_data *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
int hdcp_library_register(void **pphdcpcontext,
|
struct hdcp_register_data {
|
||||||
struct hdcp_client_ops *client_ops,
|
struct hdcp_client_ops *client_ops;
|
||||||
struct hdcp_txmtr_ops *txmtr_ops, void *client_ctx);
|
struct hdcp_txmtr_ops *txmtr_ops;
|
||||||
|
void *client_ctx;
|
||||||
|
void **hdcp_ctx;
|
||||||
|
bool tethered;
|
||||||
|
};
|
||||||
|
|
||||||
|
int hdcp_library_register(struct hdcp_register_data *data);
|
||||||
void hdcp_library_deregister(void *phdcpcontext);
|
void hdcp_library_deregister(void *phdcpcontext);
|
||||||
bool hdcp1_check_if_supported_load_app(void);
|
bool hdcp1_check_if_supported_load_app(void);
|
||||||
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
|
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
|
||||||
|
|
Loading…
Add table
Reference in a new issue