This just standardizes the use of MIN() and MAX() macros, with the very traditional semantics. The goal is to use these for C constant expressions and for top-level / static initializers, and so be able to simplify the min()/max() macros. These macro names were used by various kernel code - they are very traditional, after all - and all such users have been fixed up, with a few different approaches: - trivial duplicated macro definitions have been removed Note that 'trivial' here means that it's obviously kernel code that already included all the major kernel headers, and thus gets the new generic MIN/MAX macros automatically. - non-trivial duplicated macro definitions are guarded with #ifndef This is the "yes, they define their own versions, but no, the include situation is not entirely obvious, and maybe they don't get the generic version automatically" case. - strange use case #1 A couple of drivers decided that the way they want to describe their versioning is with #define MAJ 1 #define MIN 2 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) which adds zero value and I just did my Alexander the Great impersonation, and rewrote that pointless Gordian knot as #define DRV_VERSION "1.2" instead. - strange use case #2 A couple of drivers thought that it's a good idea to have a random 'MIN' or 'MAX' define for a value or index into a table, rather than the traditional macro that takes arguments. These values were re-written as C enum's instead. The new function-line macros only expand when followed by an open parenthesis, and thus don't clash with enum use. Happily, there weren't really all that many of these cases, and a lot of users already had the pattern of using '#ifndef' guarding (or in one case just using '#undef MIN') before defining their own private version that does the same thing. I left such cases alone. Cc: David Laight <David.Laight@aculab.com> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
690 lines
21 KiB
C
690 lines
21 KiB
C
/*
|
|
* Copyright 2019 Advanced Micro Devices, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Authors: AMD
|
|
*
|
|
*/
|
|
|
|
#include "hdcp.h"
|
|
|
|
#ifndef MIN
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
#endif
|
|
#define HDCP_I2C_ADDR 0x3a /* 0x74 >> 1*/
|
|
#define KSV_READ_SIZE 0xf /* 0x6803b - 0x6802c */
|
|
#define HDCP_MAX_AUX_TRANSACTION_SIZE 16
|
|
|
|
#define DP_CP_IRQ (1 << 2)
|
|
|
|
enum mod_hdcp_ddc_message_id {
|
|
MOD_HDCP_MESSAGE_ID_INVALID = -1,
|
|
|
|
/* HDCP 1.4 */
|
|
|
|
MOD_HDCP_MESSAGE_ID_READ_BKSV = 0,
|
|
MOD_HDCP_MESSAGE_ID_READ_RI_R0,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AKSV,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AINFO,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AN,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_X,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_0,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_1,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_2,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_3,
|
|
MOD_HDCP_MESSAGE_ID_READ_VH_4,
|
|
MOD_HDCP_MESSAGE_ID_READ_BCAPS,
|
|
MOD_HDCP_MESSAGE_ID_READ_BSTATUS,
|
|
MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO,
|
|
MOD_HDCP_MESSAGE_ID_READ_BINFO,
|
|
|
|
/* HDCP 2.2 */
|
|
|
|
MOD_HDCP_MESSAGE_ID_HDCP2VERSION,
|
|
MOD_HDCP_MESSAGE_ID_RX_CAPS,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT,
|
|
MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM,
|
|
MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME,
|
|
MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT,
|
|
MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS,
|
|
MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST,
|
|
MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST_PART2,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE,
|
|
MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY,
|
|
MOD_HDCP_MESSAGE_ID_READ_RXSTATUS,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE,
|
|
|
|
MOD_HDCP_MESSAGE_ID_MAX
|
|
};
|
|
|
|
static const uint8_t hdcp_i2c_offsets[] = {
|
|
[MOD_HDCP_MESSAGE_ID_READ_BKSV] = 0x0,
|
|
[MOD_HDCP_MESSAGE_ID_READ_RI_R0] = 0x8,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKSV] = 0x10,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AINFO] = 0x15,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AN] = 0x18,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_X] = 0x20,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_0] = 0x20,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_1] = 0x24,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_2] = 0x28,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_3] = 0x2C,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_4] = 0x30,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BCAPS] = 0x40,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BSTATUS] = 0x41,
|
|
[MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x43,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BINFO] = 0xFF,
|
|
[MOD_HDCP_MESSAGE_ID_HDCP2VERSION] = 0x50,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST_PART2] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x60,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x80,
|
|
[MOD_HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x70,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x0
|
|
};
|
|
|
|
static const uint32_t hdcp_dpcd_addrs[] = {
|
|
[MOD_HDCP_MESSAGE_ID_READ_BKSV] = 0x68000,
|
|
[MOD_HDCP_MESSAGE_ID_READ_RI_R0] = 0x68005,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKSV] = 0x68007,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AINFO] = 0x6803B,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AN] = 0x6800c,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_X] = 0x68014,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_0] = 0x68014,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_1] = 0x68018,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_2] = 0x6801c,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_3] = 0x68020,
|
|
[MOD_HDCP_MESSAGE_ID_READ_VH_4] = 0x68024,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BCAPS] = 0x68028,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BSTATUS] = 0x68029,
|
|
[MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x6802c,
|
|
[MOD_HDCP_MESSAGE_ID_READ_BINFO] = 0x6802a,
|
|
[MOD_HDCP_MESSAGE_ID_RX_CAPS] = 0x6921d,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x69000,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x6900b,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x69220,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x692a0,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x692c0,
|
|
[MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x692e0,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x692f0,
|
|
[MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x692f8,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x69318,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x69330,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST_PART2] = 0x69340,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x693e0,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x693f0,
|
|
[MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x69473,
|
|
[MOD_HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x69493,
|
|
[MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x69494
|
|
};
|
|
|
|
static enum mod_hdcp_status read(struct mod_hdcp *hdcp,
|
|
enum mod_hdcp_ddc_message_id msg_id,
|
|
uint8_t *buf,
|
|
uint32_t buf_len)
|
|
{
|
|
bool success = true;
|
|
uint32_t cur_size = 0;
|
|
uint32_t data_offset = 0;
|
|
|
|
if (msg_id == MOD_HDCP_MESSAGE_ID_INVALID ||
|
|
msg_id >= MOD_HDCP_MESSAGE_ID_MAX)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
int num_dpcd_addrs = ARRAY_SIZE(hdcp_dpcd_addrs);
|
|
if (msg_id >= num_dpcd_addrs)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
while (buf_len > 0) {
|
|
cur_size = MIN(buf_len, HDCP_MAX_AUX_TRANSACTION_SIZE);
|
|
success = hdcp->config.ddc.funcs.read_dpcd(hdcp->config.ddc.handle,
|
|
hdcp_dpcd_addrs[msg_id] + data_offset,
|
|
buf + data_offset,
|
|
cur_size);
|
|
|
|
if (!success)
|
|
break;
|
|
|
|
buf_len -= cur_size;
|
|
data_offset += cur_size;
|
|
}
|
|
} else {
|
|
int num_i2c_offsets = ARRAY_SIZE(hdcp_i2c_offsets);
|
|
if (msg_id >= num_i2c_offsets)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
success = hdcp->config.ddc.funcs.read_i2c(
|
|
hdcp->config.ddc.handle,
|
|
HDCP_I2C_ADDR,
|
|
hdcp_i2c_offsets[msg_id],
|
|
buf,
|
|
(uint32_t)buf_len);
|
|
}
|
|
|
|
return success ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_DDC_FAILURE;
|
|
}
|
|
|
|
static enum mod_hdcp_status read_repeatedly(struct mod_hdcp *hdcp,
|
|
enum mod_hdcp_ddc_message_id msg_id,
|
|
uint8_t *buf,
|
|
uint32_t buf_len,
|
|
uint8_t read_size)
|
|
{
|
|
enum mod_hdcp_status status = MOD_HDCP_STATUS_DDC_FAILURE;
|
|
uint32_t cur_size = 0;
|
|
uint32_t data_offset = 0;
|
|
|
|
while (buf_len > 0) {
|
|
cur_size = MIN(buf_len, read_size);
|
|
status = read(hdcp, msg_id, buf + data_offset, cur_size);
|
|
|
|
if (status != MOD_HDCP_STATUS_SUCCESS)
|
|
break;
|
|
|
|
buf_len -= cur_size;
|
|
data_offset += cur_size;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static enum mod_hdcp_status write(struct mod_hdcp *hdcp,
|
|
enum mod_hdcp_ddc_message_id msg_id,
|
|
uint8_t *buf,
|
|
uint32_t buf_len)
|
|
{
|
|
bool success = true;
|
|
uint32_t cur_size = 0;
|
|
uint32_t data_offset = 0;
|
|
|
|
if (msg_id == MOD_HDCP_MESSAGE_ID_INVALID ||
|
|
msg_id >= MOD_HDCP_MESSAGE_ID_MAX)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
int num_dpcd_addrs = ARRAY_SIZE(hdcp_dpcd_addrs);
|
|
if (msg_id >= num_dpcd_addrs)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
while (buf_len > 0) {
|
|
cur_size = MIN(buf_len, HDCP_MAX_AUX_TRANSACTION_SIZE);
|
|
success = hdcp->config.ddc.funcs.write_dpcd(
|
|
hdcp->config.ddc.handle,
|
|
hdcp_dpcd_addrs[msg_id] + data_offset,
|
|
buf + data_offset,
|
|
cur_size);
|
|
|
|
if (!success)
|
|
break;
|
|
|
|
buf_len -= cur_size;
|
|
data_offset += cur_size;
|
|
}
|
|
} else {
|
|
int num_i2c_offsets = ARRAY_SIZE(hdcp_i2c_offsets);
|
|
if (msg_id >= num_i2c_offsets)
|
|
return MOD_HDCP_STATUS_DDC_FAILURE;
|
|
|
|
hdcp->buf[0] = hdcp_i2c_offsets[msg_id];
|
|
memmove(&hdcp->buf[1], buf, buf_len);
|
|
success = hdcp->config.ddc.funcs.write_i2c(
|
|
hdcp->config.ddc.handle,
|
|
HDCP_I2C_ADDR,
|
|
hdcp->buf,
|
|
(uint32_t)(buf_len+1));
|
|
}
|
|
|
|
return success ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_DDC_FAILURE;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_bksv(struct mod_hdcp *hdcp)
|
|
{
|
|
return read(hdcp, MOD_HDCP_MESSAGE_ID_READ_BKSV,
|
|
hdcp->auth.msg.hdcp1.bksv,
|
|
sizeof(hdcp->auth.msg.hdcp1.bksv));
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_bcaps(struct mod_hdcp *hdcp)
|
|
{
|
|
return read(hdcp, MOD_HDCP_MESSAGE_ID_READ_BCAPS,
|
|
&hdcp->auth.msg.hdcp1.bcaps,
|
|
sizeof(hdcp->auth.msg.hdcp1.bcaps));
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_bstatus(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_BSTATUS,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp1.bstatus,
|
|
1);
|
|
else
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_BSTATUS,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp1.bstatus,
|
|
sizeof(hdcp->auth.msg.hdcp1.bstatus));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_r0p(struct mod_hdcp *hdcp)
|
|
{
|
|
return read(hdcp, MOD_HDCP_MESSAGE_ID_READ_RI_R0,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp1.r0p,
|
|
sizeof(hdcp->auth.msg.hdcp1.r0p));
|
|
}
|
|
|
|
/* special case, reading repeatedly at the same address, don't use read() */
|
|
enum mod_hdcp_status mod_hdcp_read_ksvlist(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = read_repeatedly(hdcp, MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO,
|
|
hdcp->auth.msg.hdcp1.ksvlist,
|
|
hdcp->auth.msg.hdcp1.ksvlist_size,
|
|
KSV_READ_SIZE);
|
|
else
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp1.ksvlist,
|
|
hdcp->auth.msg.hdcp1.ksvlist_size);
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_vp(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_VH_0,
|
|
&hdcp->auth.msg.hdcp1.vp[0], 4);
|
|
if (status != MOD_HDCP_STATUS_SUCCESS)
|
|
goto out;
|
|
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_VH_1,
|
|
&hdcp->auth.msg.hdcp1.vp[4], 4);
|
|
if (status != MOD_HDCP_STATUS_SUCCESS)
|
|
goto out;
|
|
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_VH_2,
|
|
&hdcp->auth.msg.hdcp1.vp[8], 4);
|
|
if (status != MOD_HDCP_STATUS_SUCCESS)
|
|
goto out;
|
|
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_VH_3,
|
|
&hdcp->auth.msg.hdcp1.vp[12], 4);
|
|
if (status != MOD_HDCP_STATUS_SUCCESS)
|
|
goto out;
|
|
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_VH_4,
|
|
&hdcp->auth.msg.hdcp1.vp[16], 4);
|
|
out:
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_binfo(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_BINFO,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp1.binfo_dp,
|
|
sizeof(hdcp->auth.msg.hdcp1.binfo_dp));
|
|
else
|
|
status = MOD_HDCP_STATUS_INVALID_OPERATION;
|
|
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_aksv(struct mod_hdcp *hdcp)
|
|
{
|
|
return write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKSV,
|
|
hdcp->auth.msg.hdcp1.aksv,
|
|
sizeof(hdcp->auth.msg.hdcp1.aksv));
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_ainfo(struct mod_hdcp *hdcp)
|
|
{
|
|
return write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AINFO,
|
|
&hdcp->auth.msg.hdcp1.ainfo,
|
|
sizeof(hdcp->auth.msg.hdcp1.ainfo));
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_an(struct mod_hdcp *hdcp)
|
|
{
|
|
return write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AN,
|
|
hdcp->auth.msg.hdcp1.an,
|
|
sizeof(hdcp->auth.msg.hdcp1.an));
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_hdcp2version(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = MOD_HDCP_STATUS_INVALID_OPERATION;
|
|
else
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_HDCP2VERSION,
|
|
&hdcp->auth.msg.hdcp2.hdcp2version_hdmi,
|
|
sizeof(hdcp->auth.msg.hdcp2.hdcp2version_hdmi));
|
|
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_rxcaps(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (!is_dp_hdcp(hdcp))
|
|
status = MOD_HDCP_STATUS_INVALID_OPERATION;
|
|
else
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_RX_CAPS,
|
|
hdcp->auth.msg.hdcp2.rxcaps_dp,
|
|
sizeof(hdcp->auth.msg.hdcp2.rxcaps_dp));
|
|
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_rxstatus(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_RXSTATUS,
|
|
&hdcp->auth.msg.hdcp2.rxstatus_dp,
|
|
1);
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_RXSTATUS,
|
|
(uint8_t *)&hdcp->auth.msg.hdcp2.rxstatus,
|
|
sizeof(hdcp->auth.msg.hdcp2.rxstatus));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_ake_cert(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
hdcp->auth.msg.hdcp2.ake_cert[0] = HDCP_2_2_AKE_SEND_CERT;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT,
|
|
hdcp->auth.msg.hdcp2.ake_cert+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_cert)-1);
|
|
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT,
|
|
hdcp->auth.msg.hdcp2.ake_cert,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_cert));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_h_prime(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
hdcp->auth.msg.hdcp2.ake_h_prime[0] = HDCP_2_2_AKE_SEND_HPRIME;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME,
|
|
hdcp->auth.msg.hdcp2.ake_h_prime+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)-1);
|
|
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME,
|
|
hdcp->auth.msg.hdcp2.ake_h_prime,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_h_prime));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_pairing_info(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
hdcp->auth.msg.hdcp2.ake_pairing_info[0] = HDCP_2_2_AKE_SEND_PAIRING_INFO;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO,
|
|
hdcp->auth.msg.hdcp2.ake_pairing_info+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)-1);
|
|
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO,
|
|
hdcp->auth.msg.hdcp2.ake_pairing_info,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_l_prime(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
hdcp->auth.msg.hdcp2.lc_l_prime[0] = HDCP_2_2_LC_SEND_LPRIME;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME,
|
|
hdcp->auth.msg.hdcp2.lc_l_prime+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)-1);
|
|
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME,
|
|
hdcp->auth.msg.hdcp2.lc_l_prime,
|
|
sizeof(hdcp->auth.msg.hdcp2.lc_l_prime));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_rx_id_list(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
uint32_t device_count = 0;
|
|
uint32_t rx_id_list_size = 0;
|
|
uint32_t bytes_read = 0;
|
|
|
|
hdcp->auth.msg.hdcp2.rx_id_list[0] = HDCP_2_2_REP_SEND_RECVID_LIST;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST,
|
|
hdcp->auth.msg.hdcp2.rx_id_list+1,
|
|
HDCP_MAX_AUX_TRANSACTION_SIZE);
|
|
if (status == MOD_HDCP_STATUS_SUCCESS) {
|
|
bytes_read = HDCP_MAX_AUX_TRANSACTION_SIZE;
|
|
device_count = HDCP_2_2_DEV_COUNT_LO(hdcp->auth.msg.hdcp2.rx_id_list[2]) +
|
|
(HDCP_2_2_DEV_COUNT_HI(hdcp->auth.msg.hdcp2.rx_id_list[1]) << 4);
|
|
rx_id_list_size = MIN((21 + 5 * device_count),
|
|
(sizeof(hdcp->auth.msg.hdcp2.rx_id_list) - 1));
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST_PART2,
|
|
hdcp->auth.msg.hdcp2.rx_id_list + 1 + bytes_read,
|
|
(rx_id_list_size - 1) / HDCP_MAX_AUX_TRANSACTION_SIZE * HDCP_MAX_AUX_TRANSACTION_SIZE);
|
|
}
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST,
|
|
hdcp->auth.msg.hdcp2.rx_id_list,
|
|
hdcp->auth.msg.hdcp2.rx_id_list_size);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_read_stream_ready(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
hdcp->auth.msg.hdcp2.repeater_auth_stream_ready[0] = HDCP_2_2_REP_STREAM_READY;
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_stream_ready+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)-1);
|
|
|
|
} else {
|
|
status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_stream_ready,
|
|
sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_ake_init(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT,
|
|
hdcp->auth.msg.hdcp2.ake_init+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_init)-1);
|
|
else
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT,
|
|
hdcp->auth.msg.hdcp2.ake_init,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_init));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_no_stored_km(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM,
|
|
hdcp->auth.msg.hdcp2.ake_no_stored_km+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)-1);
|
|
else
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM,
|
|
hdcp->auth.msg.hdcp2.ake_no_stored_km,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_stored_km(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM,
|
|
hdcp->auth.msg.hdcp2.ake_stored_km+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_stored_km)-1);
|
|
else
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM,
|
|
hdcp->auth.msg.hdcp2.ake_stored_km,
|
|
sizeof(hdcp->auth.msg.hdcp2.ake_stored_km));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_lc_init(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT,
|
|
hdcp->auth.msg.hdcp2.lc_init+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.lc_init)-1);
|
|
else
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT,
|
|
hdcp->auth.msg.hdcp2.lc_init,
|
|
sizeof(hdcp->auth.msg.hdcp2.lc_init));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_eks(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS,
|
|
hdcp->auth.msg.hdcp2.ske_eks+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.ske_eks)-1);
|
|
else
|
|
status = write(hdcp,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS,
|
|
hdcp->auth.msg.hdcp2.ske_eks,
|
|
sizeof(hdcp->auth.msg.hdcp2.ske_eks));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_repeater_auth_ack(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_ack+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack)-1);
|
|
else
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_ack,
|
|
sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack));
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_stream_manage(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_stream_manage+1,
|
|
hdcp->auth.msg.hdcp2.stream_manage_size-1);
|
|
else
|
|
status = write(hdcp,
|
|
MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE,
|
|
hdcp->auth.msg.hdcp2.repeater_auth_stream_manage,
|
|
hdcp->auth.msg.hdcp2.stream_manage_size);
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_write_content_type(struct mod_hdcp *hdcp)
|
|
{
|
|
enum mod_hdcp_status status;
|
|
|
|
if (is_dp_hdcp(hdcp))
|
|
status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE,
|
|
hdcp->auth.msg.hdcp2.content_stream_type_dp+1,
|
|
sizeof(hdcp->auth.msg.hdcp2.content_stream_type_dp)-1);
|
|
else
|
|
status = MOD_HDCP_STATUS_INVALID_OPERATION;
|
|
return status;
|
|
}
|
|
|
|
enum mod_hdcp_status mod_hdcp_clear_cp_irq_status(struct mod_hdcp *hdcp)
|
|
{
|
|
uint8_t clear_cp_irq_bit = DP_CP_IRQ;
|
|
uint32_t size = 1;
|
|
|
|
if (is_dp_hdcp(hdcp)) {
|
|
uint32_t cp_irq_addrs = (hdcp->connection.link.dp.rev >= 0x14)
|
|
? DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0:DP_DEVICE_SERVICE_IRQ_VECTOR;
|
|
return hdcp->config.ddc.funcs.write_dpcd(hdcp->config.ddc.handle, cp_irq_addrs,
|
|
&clear_cp_irq_bit, size) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_DDC_FAILURE;
|
|
}
|
|
|
|
return MOD_HDCP_STATUS_INVALID_OPERATION;
|
|
}
|