summaryrefslogtreecommitdiff
path: root/drivers/misc/hdcp.c
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2016-11-29 15:35:54 -0800
committerAjay Singh Parmar <aparmar@codeaurora.org>2016-11-30 21:09:56 -0800
commit327a852ba7d044652f4b90c557b31de597f58dab (patch)
treebee46be32191485172c0e30d54ae3f2d82c6e111 /drivers/misc/hdcp.c
parent2be8fc81c3adef891480d3abd19639860d838443 (diff)
msm: hdcp: add response timeout and new messages for sink
As per hdcp 2.2 specifications, send the stream type message to sink at a specified address in case sink is a receiver. Update the messages to be sent to sink with the message received from TZ and tear down the session in case it time's out. Also, enable encryption after stream management message exchange for hdcp repeaters to avoid unnecessary link failures. Change-Id: Ib77756c942abfbdd6e1522a3238d5d8499496fc9 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/misc/hdcp.c')
-rw-r--r--drivers/misc/hdcp.c171
1 files changed, 119 insertions, 52 deletions
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index 56ddf8467d16..011d5bd88d90 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -65,7 +65,8 @@
#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15
#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17
-#define HDCP2P2_MAX_MESSAGES 18
+#define SKE_SEND_TYPE_ID 18
+#define HDCP2P2_MAX_MESSAGES 19
#define HDCP1_SET_KEY_MESSAGE_ID 202
#define HDCP1_SET_ENC_MESSAGE_ID 205
@@ -94,7 +95,7 @@
* minimum wait as per standard is 200 ms. keep it 300 ms
* to be on safe side.
*/
-#define SLEEP_SET_HW_KEY_MS 300
+#define SLEEP_SET_HW_KEY_MS 220
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
@@ -187,6 +188,9 @@ static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
[SKE_SEND_EKS_MESSAGE_ID] = { 2,
{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
0 },
+ [SKE_SEND_TYPE_ID] = { 1,
+ { {"type", 0x69494, 1} },
+ 0 },
[REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
@@ -499,8 +503,10 @@ struct hdcp_lib_handle {
uint32_t tz_ctxhandle;
uint32_t hdcp_timeout;
uint32_t timeout_left;
+ uint32_t wait_timeout;
bool no_stored_km_flag;
bool feature_supported;
+ bool authenticated;
void *client_ctx;
struct hdcp_client_ops *client_ops;
struct mutex msg_lock;
@@ -521,7 +527,7 @@ struct hdcp_lib_handle {
enum hdcp_device_type device_type;
struct task_struct *thread;
- struct completion topo_wait;
+ struct completion poll_wait;
struct kthread_worker worker;
struct kthread_work wk_init;
@@ -529,7 +535,7 @@ struct hdcp_lib_handle {
struct kthread_work wk_msg_recvd;
struct kthread_work wk_timeout;
struct kthread_work wk_clean;
- struct kthread_work wk_topology;
+ struct kthread_work wk_wait;
struct kthread_work wk_stream;
int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
@@ -574,6 +580,7 @@ static const char *hdcp_lib_message_name(int msg_id)
{15, "REPEATER_AUTH_SEND_ACK"},
{16, "REPEATER_AUTH_STREAM_MANAGE"},
{17, "REPEATER_AUTH_STREAM_READY"},
+ {18, "SKE_SEND_TYPE_ID"},
};
int i;
@@ -612,8 +619,14 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
case LC_SEND_L_PRIME_MESSAGE_ID:
return SKE_SEND_EKS_MESSAGE_ID;
case SKE_SEND_EKS_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return SKE_SEND_TYPE_ID;
+ case SKE_SEND_TYPE_ID:
case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return INVALID_MESSAGE_ID;
+
if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE)
return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
else
@@ -628,6 +641,33 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
}
}
+static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
+ struct hdmi_hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ handle->wait_timeout = HZ;
+ else
+ handle->wait_timeout = HZ / 4;
+ break;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ handle->wait_timeout = HZ / 4;
+ break;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ if (!handle->authenticated)
+ handle->wait_timeout = HZ * 3;
+ else
+ handle->wait_timeout = 0;
+ break;
+ default:
+ handle->wait_timeout = 0;
+ }
+
+ if (handle->wait_timeout)
+ queue_kthread_work(&handle->worker, &handle->wk_wait);
+}
+
static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
struct hdmi_hdcp_wakeup_data *data)
{
@@ -639,43 +679,42 @@ static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
- if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE ||
- data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
- data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) {
+ if (data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
+ data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL)
handle->last_msg = hdcp_lib_get_next_message(handle, data);
+ if (handle->last_msg != INVALID_MESSAGE_ID &&
+ data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS &&
+ data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_FAILED) {
+ u32 msg_num, rx_status;
+ const struct hdcp_msg_part *msg;
+
pr_debug("lib->client: %s (%s)\n",
hdmi_hdcp_cmd_to_str(data->cmd),
hdcp_lib_message_name(handle->last_msg));
- if (handle->last_msg > INVALID_MESSAGE_ID &&
- handle->last_msg < HDCP2P2_MAX_MESSAGES) {
- u32 msg_num, rx_status;
- const struct hdcp_msg_part *msg;
-
- data->message_data = &hdcp_msg_lookup[handle->last_msg];
+ data->message_data = &hdcp_msg_lookup[handle->last_msg];
- msg_num = data->message_data->num_messages;
- msg = data->message_data->messages;
- rx_status = data->message_data->rx_status;
+ msg_num = data->message_data->num_messages;
+ msg = data->message_data->messages;
+ rx_status = data->message_data->rx_status;
- pr_debug("rxstatus 0x%x\n", rx_status);
- pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
+ pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
- for (i = 0; i < msg_num; i++)
- pr_debug("%10s | %6x | %4d\n",
- msg[i].name, msg[i].offset,
- msg[i].length);
- }
+ for (i = 0; i < msg_num; i++)
+ pr_debug("%10s | %6x | %4d\n",
+ msg[i].name, msg[i].offset,
+ msg[i].length);
} else {
- pr_debug("lib->client: %s\n",
- hdmi_hdcp_cmd_to_str(data->cmd));
+ pr_debug("lib->client: %s\n", hdmi_hdcp_cmd_to_str(data->cmd));
}
rc = handle->client_ops->wakeup(data);
if (rc)
pr_err("error sending %s to client\n",
hdmi_hdcp_cmd_to_str(data->cmd));
+
+ hdcp_lib_wait_for_response(handle, data);
}
static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
@@ -1286,6 +1325,8 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->message[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->message[0];
+
/* send the response to HDMI driver */
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
@@ -1404,6 +1445,8 @@ static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->message[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->message[0];
+
/* send the response to HDMI driver */
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
@@ -1470,6 +1513,8 @@ static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
pr_debug("message received from TZ: %s\n",
hdcp_lib_message_name((int)rsp_buf->msg[0]));
+ handle->last_msg = (int)rsp_buf->msg[0];
+
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
rsp_buf->msglen);
@@ -1550,11 +1595,11 @@ static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
if (handle->worker.current_work == &handle->wk_clean)
pr_debug("clean work executing\n");
- if (!list_empty(&handle->wk_topology.node))
- pr_debug("topology work queued\n");
+ if (!list_empty(&handle->wk_wait.node))
+ pr_debug("wait work queued\n");
- if (handle->worker.current_work == &handle->wk_topology)
- pr_debug("topology work executing\n");
+ if (handle->worker.current_work == &handle->wk_wait)
+ pr_debug("wait work executing\n");
if (!list_empty(&handle->wk_stream.node))
pr_debug("stream work queued\n");
@@ -1613,7 +1658,7 @@ static void hdcp_lib_update_exec_type(void *ctx, bool tethered)
mutex_unlock(&handle->wakeup_mutex);
}
-static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
+static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
{
struct hdcp_lib_handle *handle;
int rc = 0;
@@ -1630,8 +1675,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
handle->wakeup_cmd = data->cmd;
handle->timeout_left = data->timeout;
- pr_debug("client->lib: %s\n",
- hdcp_lib_cmd_to_str(handle->wakeup_cmd));
+ pr_debug("client->lib: %s (%s)\n",
+ hdcp_lib_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
rc = hdcp_lib_check_valid_state(handle);
if (rc)
@@ -1655,8 +1701,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
}
mutex_unlock(&handle->msg_lock);
- if (!completion_done(&handle->topo_wait))
- complete_all(&handle->topo_wait);
+ if (!completion_done(&handle->poll_wait))
+ complete_all(&handle->poll_wait);
switch (handle->wakeup_cmd) {
case HDCP_LIB_WKUP_CMD_START:
@@ -1719,22 +1765,30 @@ static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
cdata.context = handle->client_ctx;
switch (handle->last_msg_sent) {
- case SKE_SEND_EKS_MESSAGE_ID:
- if (handle->repeater_flag) {
- if (!atomic_read(&handle->hdcp_off))
- queue_kthread_work(&handle->worker,
- &handle->wk_topology);
- }
-
+ case SKE_SEND_TYPE_ID:
if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
hdcp_lib_wakeup_client(handle, &cdata);
+ }
+ /* poll for link check */
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
+ break;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (handle->repeater_flag) {
/* poll for link check */
cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
} else {
- if (!atomic_read(&handle->hdcp_off))
- HDCP_LIB_EXECUTE(clean);
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ handle->listener_buf[0] = SKE_SEND_TYPE_ID;
+ handle->msglen = 2;
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ handle->last_msg = hdcp_lib_get_next_message(handle,
+ &cdata);
}
break;
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
@@ -1915,6 +1969,8 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
return;
}
+ handle->authenticated = false;
+
hdcp_lib_txmtr_deinit(handle);
if (!handle->legacy_app)
hdcp_lib_session_deinit(handle);
@@ -2040,6 +2096,13 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
(rc == 0) && (rsp_buf->status == 0)) {
pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
+ if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
goto exit;
}
@@ -2057,6 +2120,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->msg[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->msg[0];
+
/* set the flag if response is AKE_No_Stored_km */
if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
pr_debug("Setting no_stored_km_flag\n");
@@ -2101,12 +2166,11 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
hdcp_lib_msg_recvd(handle);
}
-static void hdcp_lib_topology_work(struct kthread_work *work)
+static void hdcp_lib_wait_work(struct kthread_work *work)
{
u32 timeout;
struct hdcp_lib_handle *handle = container_of(work,
- struct hdcp_lib_handle,
- wk_topology);
+ struct hdcp_lib_handle, wk_wait);
if (!handle) {
pr_err("invalid input\n");
@@ -2123,14 +2187,17 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
return;
}
- reinit_completion(&handle->topo_wait);
- timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3);
+ reinit_completion(&handle->poll_wait);
+ timeout = wait_for_completion_timeout(&handle->poll_wait,
+ handle->wait_timeout);
if (!timeout) {
- pr_err("topology receiver id list timeout\n");
+ pr_err("wait timeout\n");
if (!atomic_read(&handle->hdcp_off))
HDCP_LIB_EXECUTE(clean);
}
+
+ handle->wait_timeout = 0;
}
bool hdcp1_check_if_supported_load_app(void)
@@ -2266,7 +2333,7 @@ int hdcp_library_register(struct hdcp_register_data *data)
/* populate ops to be called by client */
data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
- data->txmtr_ops->wakeup = hdcp_lib_wakeup;
+ data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type;
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
@@ -2296,10 +2363,10 @@ int hdcp_library_register(struct hdcp_register_data *data)
init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work);
- init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work);
+ init_kthread_work(&handle->wk_wait, hdcp_lib_wait_work);
init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work);
- init_completion(&handle->topo_wait);
+ init_completion(&handle->poll_wait);
handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
if (!(handle->listener_buf)) {