This is an automatic generated email to let you know that the following patch 
were queued:

Subject: edid-decode: add Cable ID support
Author:  Hans Verkuil <hverkuil-ci...@xs4all.nl>
Date:    Tue Aug 20 11:54:09 2024 +0200

Add Cable ID support.

Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>

 ddc.cpp         | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 edid-decode.cpp |   5 +++
 edid-decode.h   |   2 +
 3 files changed, 134 insertions(+)

---

diff --git a/ddc.cpp b/ddc.cpp
index b9640d8c71f2..da65e177d337 100644
--- a/ddc.cpp
+++ b/ddc.cpp
@@ -552,3 +552,130 @@ int read_scdc(int adapter_fd, bool update_only)
        }
        return 0;
 }
+
+static __u8 checksum(const __u8 *hdr, const __u8 *data, unsigned len)
+{
+       __u8 sum = 0;
+
+       for (int i = 0; i < 5; i++)
+               sum += hdr[i];
+       while (len--)
+               sum += *data++;
+       return 256 - sum;
+}
+
+static int idcc_read(int adapter_fd, __u8 cmd, __u8 *data, __u16 len)
+{
+       struct i2c_rdwr_ioctl_data i2c_data;
+       struct i2c_msg write_message;
+       struct i2c_msg read_message;
+       int err;
+
+       write_message = {
+               .addr = EDID_ADDR,
+               .len = 1,
+               .buf = &cmd
+       };
+       read_message = {
+               .addr = EDID_ADDR,
+               .flags = I2C_M_RD,
+               .len = len,
+               .buf = data
+       };
+
+       struct i2c_msg msgs[2] = { write_message, read_message };
+
+       i2c_data.msgs = msgs;
+       i2c_data.nmsgs = ARRAY_SIZE(msgs);
+       err = ioctl(adapter_fd, I2C_RDWR, &i2c_data);
+
+       if (err >= 0)
+               err = err == 2 ? 0 : -EIO;
+       if (err < 0)
+               fprintf(stderr, "Unable to read IDCC: %s\n", strerror(errno));
+       return err;
+}
+
+#if 0
+static int idcc_write_block(int adapter_fd, const __u8 *data, unsigned len)
+{
+       __u8 dummy = 0;
+       int ret = 0;
+
+       while (!ret && len--)
+               ret = idcc_read(adapter_fd, *data++, &dummy, 1);
+
+       return ret;
+}
+#endif
+
+static int idcc_read_block(int adapter_fd, const __u8 *data, unsigned len, 
__u8 *res, unsigned len2)
+{
+       __u8 dummy = 0;
+       int ret = 0;
+
+       while (!ret && len--)
+               ret = idcc_read(adapter_fd, *data++, len ? &dummy : res, len ? 
1 : len2);
+
+       return ret;
+}
+
+int read_cable_id(int adapter_fd)
+{
+       const __u8 cable_id[] = { 0xae, 0x6e, 0x61, 0x00, 0x04, 0x01 };
+       __u8 cable_man_id[] = { 0xae, 0x6e, 0x61, 0xd0, 0x04, 0x01 };
+       __u8 data[49] = {};
+
+       //__u8 source_id[] = { 0xae, 0x6e, 0x60, 0x00, 0x01, 0xff, 0 };
+       //source_id[6] = checksum(source_id, source_id + 5, 1);
+       //idcc_write_block(adapter_fd, source_id, 7);
+
+       idcc_read_block(adapter_fd, cable_id, 6, data, 5);
+       if (data[4] == checksum(cable_id, data, 4)) {
+               printf("Cable ID:\n\tCat3: %c Cat2: %c Cat1: %c\n",
+                      (data[0] & 4) ? 'n' : 'y',
+                      (data[0] & 2) ? 'n' : 'y',
+                      (data[0] & 1) ? 'n' : 'y');
+               printf("\tPCA_ON: %c MonoDirErr: %c MonoDir: %c PCA_DEP: %c 
HEAC: %c\n",
+                      (data[1] & 0x10) ? 'n' : 'y',
+                      (data[1] & 0x08) ? 'n' : 'y',
+                      (data[1] & 0x04) ? 'n' : 'y',
+                      (data[1] & 0x02) ? 'n' : 'y',
+                      (data[1] & 0x01) ? 'n' : 'y');
+               printf("\tRND: 0x%04x\n", (data[3] << 8) | data[2]);
+       }
+       bool valid = true;
+       for (unsigned i = 0; i < sizeof(data) - 1; i += 4) {
+               cable_man_id[3] = 0xd0 + i;
+               idcc_read_block(adapter_fd, cable_man_id, 6, data + i, 5);
+               if (data[i + 4] != checksum(cable_man_id, data + i, 4)) {
+                   valid = false;
+                   break;
+               }
+       }
+       if (valid) {
+               bool all_ff = true;
+
+               for (unsigned i = 0; i < sizeof(data) - 1; i++) {
+                       if (data[i] != 0xff) {
+                               all_ff = false;
+                               break;
+                       }
+               }
+               if (all_ff) {
+                       printf("Cable ID - Manufacturer Specific: all values 
are 0xff\n");
+               } else {
+                       printf("Cable ID - Manufacturer Specific:\n");
+                       printf("\tManufacturer OUI: %02x-%02x-%02x\n", data[0], 
data[1], data[2]);
+                       printf("\tDevice ID: %s\n", "");
+                       printf("\tHW Rev: %u.%u\n", data[11] >> 4, data[11] & 
0xf);
+                       printf("\tSW Rev: %u.%u\n", data[12], data[13]);
+                       printf("\tManufacturer Specific:\n\t\t");
+                       for (unsigned i = 14; i < sizeof(data) - 1; i++)
+                               printf(" %02x", data[i]);
+                       printf("\n");
+               }
+       }
+
+       return 0;
+}
diff --git a/edid-decode.cpp b/edid-decode.cpp
index dc019387801d..b696535b525b 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -68,6 +68,7 @@ enum Option {
        OptI2CSCDCUpdate,
        OptI2CHDCP,
        OptI2CHDCPRi,
+       OptI2CCableID,
        OptSTD,
        OptDMT,
        OptVIC,
@@ -116,6 +117,7 @@ static struct option long_options[] = {
        { "i2c-scdc", no_argument, 0, OptI2CSCDC },
        { "i2c-hdcp", no_argument, 0, OptI2CHDCP },
        { "i2c-hdcp-ri", required_argument, 0, OptI2CHDCPRi },
+       { "i2c-cable-id", no_argument, 0, OptI2CCableID },
 #endif
        { "std", required_argument, 0, OptSTD },
        { "dmt", required_argument, 0, OptDMT },
@@ -177,6 +179,7 @@ static void usage(void)
               "  --i2c-scdc-update     Read the SCDC Update information (bytes 
0x10-0x11) from the DDC lines.\n"
               "  --i2c-hdcp            Read the HDCP from the DDC lines.\n"
               "  --i2c-hdcp-ri=<t>     Read and print the HDCP Ri information 
every <t> seconds.\n"
+              "  --i2c-cable-id        Read the Cable ID from the DDC lines.\n"
 #endif
               "  --std <byte1>,<byte2> Show the standard timing represented by 
these two bytes.\n"
               "  --dmt <dmt>           Show the timings for the DMT with the 
given DMT ID.\n"
@@ -2472,6 +2475,8 @@ int main(int argc, char **argv)
                                ret = read_hdcp(adapter_fd);
                        if (!ret && options[OptI2CHDCPRi])
                                ret = read_hdcp_ri(adapter_fd, hdcp_ri_sleep);
+                       if (!ret && options[OptI2CCableID])
+                               ret = read_cable_id(adapter_fd);
                } else if (options[OptInfoFrame] && !options[OptGTF]) {
                        ret = 0;
                } else {
diff --git a/edid-decode.h b/edid-decode.h
index 279f77186fa9..738d84cba3e4 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -622,6 +622,7 @@ int read_edid(int adapter_fd, unsigned char *edid);
 int read_hdcp(int adapter_fd);
 int read_hdcp_ri(int adapter_fd, double ri_time);
 int read_scdc(int adapter_fd, bool update_only);
+int read_cable_id(int adapter_fd);
 
 #else
 
@@ -629,6 +630,7 @@ static inline int read_edid(int adapter_fd, unsigned char 
*edid) { return -ENODE
 static inline int read_hdcp(int adapter_fd) { return -ENODEV; }
 static inline int read_hdcp_ri(int adapter_fd, double ri_time) { return 
-ENODEV; }
 static inline int read_scdc(int adapter_fd, bool update_only) { return 
-ENODEV; }
+static inline int read_cable_id(int adapter_fd) { return -ENODEV; }
 
 #endif
 

Reply via email to