This is an automatic generated email to let you know that the following patch 
were queued at the 
http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:

Subject: edid-decode: add --hdcp option to parse an HDCP hex dump
Author:  Hans Verkuil <[email protected]>
Date:    Mon May 11 08:13:14 2026 +0200

With the --i2c-hdcp option you can read the HDCP data. If that is
saved to a file, then it can be parsed later with the --hdcp option.

Signed-off-by: Hans Verkuil <[email protected]>

 utils/edid-decode/ddc.cpp          |  20 +++---
 utils/edid-decode/edid-decode.1.in |   3 +
 utils/edid-decode/edid-decode.cpp  | 124 +++++++++++++++++++++++++++++++++++--
 utils/edid-decode/edid-decode.h    |   8 +--
 utils/edid-decode/parse-hdcp.cpp   |  22 ++-----
 5 files changed, 138 insertions(+), 39 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=4a416ee511b710833e5ce759ba71c7d9b4b0e4fb
diff --git a/utils/edid-decode/ddc.cpp b/utils/edid-decode/ddc.cpp
index 209ef6aef230..a74e884a4706 100644
--- a/utils/edid-decode/ddc.cpp
+++ b/utils/edid-decode/ddc.cpp
@@ -41,9 +41,6 @@
 #define EDID_ADDR 0x50
 #define SEGMENT_POINTER_ADDR 0x30
 
-// i2c address for SCDC
-#define SCDC_ADDR 0x54
-
 // i2c addresses for HDCP
 #define HDCP_PRIM_ADDR 0x3a
 #define HDCP_SEC_ADDR 0x3b
@@ -285,8 +282,7 @@ static int read_hdcp_registers(int adapter_fd, __u8 
*hdcp_prim, __u8 *hdcp_sec,
                msgs[1].buf = hdcp_prim + 129;
                err = ioctl(adapter_fd, I2C_RDWR, &data);
        }
-
-       if (err < 0) {
+       if (err != 2) {
                fprintf(stderr, "Unable to read Primary Link HDCP: %s\n",
                        strerror(errno));
                return -1;
@@ -310,7 +306,7 @@ static int read_hdcp_registers(int adapter_fd, __u8 
*hdcp_prim, __u8 *hdcp_sec,
                data.msgs = ksv_fifo_msgs;
                data.nmsgs = ARRAY_SIZE(msgs);
                err = ioctl(adapter_fd, I2C_RDWR, &data);
-               if (err < 0) {
+               if (err != 2) {
                        fprintf(stderr, "Unable to read KSV FIFO: %s\n",
                                strerror(errno));
                        return -1;
@@ -344,17 +340,15 @@ static int read_hdcp_registers(int adapter_fd, __u8 
*hdcp_prim, __u8 *hdcp_sec,
        return 0;
 }
 
-int edid_state::read_hdcp(int adapter_fd)
+int read_hdcp(int adapter_fd, parse_data &pdata)
 {
-       __u8 hdcp_prim[256] = {};
-       __u8 hdcp_sec[256] = {};
-       __u8 ksv_fifo[128 * 5] = {};
+       __u8 *hdcp_prim = &pdata.buf[0];
+       __u8 *ksv_fifo = hdcp_prim + 256;
+       __u8 *hdcp_sec = ksv_fifo + 128 * 5;
 
-       hdcp_prim[5] = 0xdd;
-       hdcp_sec[5] = 0xdd;
        if (read_hdcp_registers(adapter_fd, hdcp_prim, hdcp_sec, ksv_fifo))
                return -1;
-       parse_hdcp_data(hdcp_prim, hdcp_sec, ksv_fifo);
+       pdata.buf_size = pdata.buf_max_size;
        return 0;
 }
 
diff --git a/utils/edid-decode/edid-decode.1.in 
b/utils/edid-decode/edid-decode.1.in
index 5f5361d69497..9b93b1a8f3a1 100644
--- a/utils/edid-decode/edid-decode.1.in
+++ b/utils/edid-decode/edid-decode.1.in
@@ -238,6 +238,9 @@ On Linux systems ELD can be extracted via the amixer 
command (copy all hex after
     
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
 
+.TP
+\fB\-J\fR, \fB\-\-hdcp\fR \fI<file>\fR
+Parse the given HDCP file. Read data from stdin if '-' was passed as argument.
 .TP
 \fB\-\-diagonal\fR \fI<inches>\fR
 Specify the diagonal of the display in inches. This will enable additional 
checks
diff --git a/utils/edid-decode/edid-decode.cpp 
b/utils/edid-decode/edid-decode.cpp
index dcb0c88cba21..00092f2108b0 100644
--- a/utils/edid-decode/edid-decode.cpp
+++ b/utils/edid-decode/edid-decode.cpp
@@ -49,6 +49,7 @@ enum Option {
        OptHelp = 'h',
        OptOnlyHexDump = 'H',
        OptInfoFrame = 'I',
+       OptHDCP = 'J',
        OptLongTimings = 'L',
        OptNativeResolution = 'n',
        OptNTSC = 'N',
@@ -133,6 +134,7 @@ static struct option long_options[] = {
        { "list-rids", no_argument, 0, OptListRIDs },
        { "infoframe", required_argument, 0, OptInfoFrame },
        { "eld", required_argument, 0, OptEld },
+       { "hdcp", required_argument, 0, OptHDCP },
        { 0, 0, 0, 0 }
 };
 
@@ -233,6 +235,7 @@ static void usage(void)
               "                        This option can be specified multiple 
times for different InfoFrame files.\n"
               "  -E, --eld <file>      Parse the EDID-Like Data, ELD from 
<file> (or stdin if '-' was specified).\n"
               "                        This option can be specified multiple 
times for different ELD files.\n"
+              "  -J, --hdcp <file>     Parse the HDCP data from <file> (or 
stdin if '-' was specified).\n"
               "  -h, --help            Display this help message.\n");
 }
 #endif
@@ -1660,7 +1663,7 @@ int edid_state::parse_edid()
        return failures ? -2 : 0;
 }
 
-/* InfoFrame/ELD parsing */
+/* InfoFrame/HDCP/ELD parsing */
 
 static unsigned char infoframe[32];
 
@@ -1680,6 +1683,16 @@ static struct parse_data eld_pdata = {
        0
 };
 
+// primary data, KSV FIFO data, and secondary data
+static unsigned char hdcp[256 + 128 * 5 + 256];
+
+static struct parse_data hdcp_pdata = {
+       "HDCP",
+       hdcp,
+       sizeof(hdcp),
+       0
+};
+
 static bool data_add_byte(parse_data &pdata, const char *s)
 {
        char buf[3];
@@ -1975,6 +1988,82 @@ int edid_state::parse_eld_file(const std::string &fname)
        return failures ? -2 : 0;
 }
 
+static int hdcp_from_file(parse_data &pdata, const char *from_file)
+{
+       int ret = data_from_file(pdata, from_file);
+
+       if (ret < 0)
+               return ret;
+
+       unsigned char *hdcp_prim = &pdata.buf[0];
+       unsigned char *ksv_fifo = hdcp_prim + 256;
+       unsigned char *hdcp_sec = ksv_fifo + 128 * 5;
+       unsigned kvs_fifo_sz = hdcp_prim[0x41] & 0x7f;
+       memcpy(hdcp_sec, ksv_fifo + kvs_fifo_sz * 5, 256);
+       memset(ksv_fifo + kvs_fifo_sz * 5, 0, (128 - kvs_fifo_sz) * 5);
+       return 0;
+}
+
+int edid_state::parse_hdcp_pdata(parse_data &pdata)
+{
+       state.block_nr = 0;
+       state.data_block.clear();
+
+       if (!options[OptSkipHexDump]) {
+               printf("edid-decode %s (hex):\n\n", pdata.name);
+               // Primary HDCP data
+               hex_block("", pdata.buf, 128, false);
+               printf("\n");
+               hex_block("", pdata.buf + 128, 128, false);
+               printf("\n");
+               // KSV FIFO
+               for (unsigned i = 0; i < (pdata.buf[0x41] & 0x7f); i++) {
+                       hex_block("", pdata.buf + 256 + i * 5, 5, false);
+                       printf("\n");
+               }
+               // Secondary HDCP data if present
+               if (!memchk(pdata.buf + 256 + 128 * 5, 256)) {
+                       hex_block("", pdata.buf + 256 + 128 * 5, 128, false);
+                       printf("\n");
+                       hex_block("", pdata.buf + 256 + 128 * 5 + 128, 128, 
false);
+                       printf("\n");
+               }
+               if (options[OptOnlyHexDump])
+                       return 0;
+               printf("----------------\n\n");
+       }
+
+       if (pdata.buf_size < 128) {
+               fail("%s is too small to parse.\n", pdata.name);
+               return -1;
+       }
+
+       parse_hdcp(pdata.buf, pdata.buf_size);
+
+       if (!options[OptCheck] && !options[OptCheckInline])
+               return 0;
+
+       printf("\n----------------\n");
+
+       if (!options[OptSkipSHA] && strlen(STRING(SHA))) {
+               options[OptSkipSHA] = 1;
+               printf("\n");
+               print_version();
+       }
+
+       if (options[OptCheck]) {
+               if (warnings)
+                       show_data_msgs(pdata.name, true);
+               if (failures)
+                       show_data_msgs(pdata.name, false);
+       }
+
+       printf("\n%s conformity: %s\n",
+              state.data_block.empty() ? pdata.name : state.data_block.c_str(),
+              failures ? "FAIL" : "PASS");
+       return failures ? -2 : 0;
+}
+
 #ifndef __EMSCRIPTEN__
 
 static unsigned char crc_calc(const unsigned char *b)
@@ -2530,6 +2619,7 @@ int main(int argc, char **argv)
        double hdcp_ri_sleep = 0;
        std::vector<std::string> if_names;
        std::vector<std::string> eld_names;
+       std::string hdcp_name;
        unsigned test_rel_duration = 0;
        unsigned test_rel_msleep = 50;
        unsigned idx = 0;
@@ -2683,6 +2773,9 @@ int main(int argc, char **argv)
                case OptInfoFrame:
                        if_names.push_back(optarg);
                        break;
+               case OptHDCP:
+                       hdcp_name = optarg;
+                       break;
                case OptEld:
                        eld_names.push_back(optarg);
                        break;
@@ -2740,13 +2833,14 @@ int main(int argc, char **argv)
                                ret = 0;
                        }
                } else if (adapter_fd >= 0) {
-                       if (options[OptI2CHDCP])
-                               ret = state.read_hdcp(adapter_fd);
-                       if (options[OptI2CHDCPRi])
+                       if (!ret && options[OptI2CHDCP])
+                               ret = read_hdcp(adapter_fd, hdcp_pdata);
+                       if (!ret && options[OptI2CHDCPRi])
                                ret = read_hdcp_ri(adapter_fd, hdcp_ri_sleep);
                        if (options[OptI2CTestReliability])
                                ret = test_reliability(adapter_fd, 
test_rel_duration, test_rel_msleep);
-               } else if ((options[OptInfoFrame] || options[OptEld]) && 
!options[OptGTF]) {
+               } else if ((options[OptInfoFrame] || options[OptEld] ||
+                           options[OptHDCP]) && !options[OptGTF]) {
                        ret = 0;
                } else {
                        ret = edid_from_file("-", stdout);
@@ -2795,6 +2889,26 @@ int main(int argc, char **argv)
 
        bool show_line = state.edid_size;
 
+       if (hdcp_name.length()) {
+               int r = hdcp_from_file(hdcp_pdata, hdcp_name.c_str());
+               if (r && !ret)
+                       ret = r;
+       }
+       if (hdcp_pdata.buf_size) {
+               if (show_line)
+                       printf("\n================\n\n");
+               show_line = true;
+
+               state.warnings = state.failures = 0;
+               for (unsigned i = 0; i < EDID_MAX_BLOCKS + 1; i++) {
+                       s_msgs[i][0].clear();
+                       s_msgs[i][1].clear();
+               }
+               int r = state.parse_hdcp_pdata(hdcp_pdata);
+               if (r && !ret)
+                       ret = r;
+       }
+
        for (const auto &n : if_names) {
                if (show_line)
                        printf("\n================\n\n");
diff --git a/utils/edid-decode/edid-decode.h b/utils/edid-decode/edid-decode.h
index 39b5dfbf3c5e..8ecd44f312fd 100644
--- a/utils/edid-decode/edid-decode.h
+++ b/utils/edid-decode/edid-decode.h
@@ -565,10 +565,8 @@ struct edid_state {
        int parse_eld_file(const std::string &fname);
        void parse_eld_baseline(const unsigned char *x, unsigned size);
 
-       int read_hdcp(int adapter_fd);
-       void parse_hdcp_data(const unsigned char hdcp_prim[256],
-                            const unsigned char hdcp_sec[256],
-                            const unsigned char ksv_fifo[128 * 5]);
+       int parse_hdcp_pdata(parse_data &pdata);
+       void parse_hdcp(const unsigned char *hdcp, unsigned size);
 };
 
 static inline void add_str(std::string &s, const std::string &add)
@@ -657,7 +655,7 @@ char *extract_string(const unsigned char *x, unsigned len, 
bool is_cp437);
 int request_i2c_adapter(const char *device);
 int read_edid(int adapter_fd, unsigned char *edid, bool silent = false);
 int test_reliability(int adapter_fd, unsigned secs, unsigned msleep);
-int read_hdcp(int adapter_fd);
+int read_hdcp(int adapter_fd, parse_data &pdata);
 int read_hdcp_ri(int adapter_fd, double ri_time);
 
 #else
diff --git a/utils/edid-decode/parse-hdcp.cpp b/utils/edid-decode/parse-hdcp.cpp
index 3359e1accd99..ded77ea6c2ce 100644
--- a/utils/edid-decode/parse-hdcp.cpp
+++ b/utils/edid-decode/parse-hdcp.cpp
@@ -9,22 +9,12 @@
 
 #include "edid-decode.h"
 
-void edid_state::parse_hdcp_data(const unsigned char hdcp_prim[256],
-                                const unsigned char hdcp_sec[256],
-                                const unsigned char ksv_fifo[128 * 5])
+void edid_state::parse_hdcp(const unsigned char *hdcp, unsigned size)
 {
-       printf("HDCP Primary Link Hex Dump:\n\n");
-       hex_block("", hdcp_prim, 128, false);
-       printf("\n");
-       hex_block("", hdcp_prim + 128, 128, false);
-       printf("\n");
-       if (hdcp_sec[5] != 0xdd) {
-               printf("HDCP Secondary Link Hex Dump:\n\n");
-               hex_block("", hdcp_sec, 128, false);
-               printf("\n");
-               hex_block("", hdcp_sec + 128, 128, false);
-               printf("\n");
-       }
+       const unsigned char *hdcp_prim = hdcp;
+       const unsigned char *ksv_fifo = hdcp + 256;
+       const unsigned char *hdcp_sec = hdcp + 256 + 128 * 5;
+
        printf("HDCP Primary Link:\n\n");
        printf("Bksv: %02x %02x %02x %02x %02x\n",
               hdcp_prim[0], hdcp_prim[1], hdcp_prim[2], hdcp_prim[3], 
hdcp_prim[4]);
@@ -89,7 +79,7 @@ void edid_state::parse_hdcp_data(const unsigned char 
hdcp_prim[256],
        if (vv & 0x800)
                printf("\tREAUTH_REQ\n");
 
-       if (hdcp_sec[5] == 0xdd)
+       if (memchk(hdcp_sec, 256))
                return;
 
        printf("HDCP Secondary Link:\n\n");
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to