edid-decode: fix emscripten build
[edid-decode.git] / ddc.cpp
blob6bdd50b2991b3d0bd298de7f58df3364f7f1066b
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Author: Hans Verkuil <hverkuil-cisco@xs4all.nl>
6 */
8 #ifndef __EMSCRIPTEN__
10 #include <cctype>
11 #include <cerrno>
12 #include <csignal>
13 #include <cstring>
14 #include <ctime>
15 #include <string>
17 #include <fcntl.h>
18 #include <getopt.h>
19 #include <sys/ioctl.h>
20 #include <sys/epoll.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <math.h>
25 #include <dirent.h>
27 #include <linux/i2c-dev.h>
28 #include <linux/i2c.h>
29 #include <linux/types.h>
31 #include "edid-decode.h"
33 // i2c addresses for edid
34 #define EDID_ADDR 0x50
35 #define SEGMENT_POINTER_ADDR 0x30
37 // i2c address for SCDC
38 #define SCDC_ADDR 0x54
40 // i2c addresses for HDCP
41 #define HDCP_PRIM_ADDR 0x3a
42 #define HDCP_SEC_ADDR 0x3b
44 int request_i2c_adapter(unsigned adapnr)
46 std::string i2c_adapter = "/dev/i2c-" + std::to_string(adapnr);
47 int fd = open(i2c_adapter.c_str(), O_RDWR);
49 if (fd >= 0)
50 return fd;
51 fprintf(stderr, "Error accessing i2c adapter %s\n", i2c_adapter.c_str());
52 return fd;
55 static int read_edid_block(int adapter_fd, __u8 *edid,
56 uint8_t segment, uint8_t offset, uint8_t blocks)
58 struct i2c_rdwr_ioctl_data data;
59 struct i2c_msg write_message;
60 struct i2c_msg read_message;
61 struct i2c_msg seg_message;
62 int err;
64 seg_message = {
65 .addr = SEGMENT_POINTER_ADDR,
66 .len = 1,
67 .buf = &segment
69 write_message = {
70 .addr = EDID_ADDR,
71 .len = 1,
72 .buf = &offset
74 read_message = {
75 .addr = EDID_ADDR,
76 .flags = I2C_M_RD,
77 .len = (__u16)(blocks * EDID_PAGE_SIZE),
78 .buf = edid
81 if (segment) {
82 struct i2c_msg msgs[2] = { seg_message, read_message };
84 data.msgs = msgs;
85 data.nmsgs = ARRAY_SIZE(msgs);
86 err = ioctl(adapter_fd, I2C_RDWR, &data);
87 } else {
88 struct i2c_msg msgs[2] = { write_message, read_message };
90 data.msgs = msgs;
91 data.nmsgs = ARRAY_SIZE(msgs);
92 err = ioctl(adapter_fd, I2C_RDWR, &data);
95 if (err < 0) {
96 fprintf(stderr, "Unable to read edid: %s\n", strerror(errno));
97 return err;
99 return 0;
102 int read_edid(int adapter_fd, unsigned char *edid)
104 unsigned n_extension_blocks;
105 int err;
107 err = read_edid_block(adapter_fd, edid, 0, 0, 2);
108 if (err)
109 return err;
110 n_extension_blocks = edid[126];
111 if (!n_extension_blocks)
112 return 1;
113 for (unsigned i = 2; i <= n_extension_blocks; i += 2) {
114 err = read_edid_block(adapter_fd, edid + i * 128, i / 2, 0,
115 (i + 1 > n_extension_blocks ? 1 : 2));
116 if (err)
117 return err;
119 return n_extension_blocks + 1;
122 static int read_hdcp_registers(int adapter_fd, __u8 *hdcp_prim, __u8 *hdcp_sec, __u8 *ksv_fifo)
124 struct i2c_rdwr_ioctl_data data;
125 struct i2c_msg write_message;
126 struct i2c_msg read_message;
127 __u8 offset = 0;
128 __u8 ksv_fifo_offset = 0x43;
129 int err;
131 write_message = {
132 .addr = HDCP_PRIM_ADDR,
133 .len = 1,
134 .buf = &offset
136 read_message = {
137 .addr = HDCP_PRIM_ADDR,
138 .flags = I2C_M_RD,
139 .len = 256,
140 .buf = hdcp_prim
143 struct i2c_msg msgs[2] = { write_message, read_message };
145 data.msgs = msgs;
146 data.nmsgs = ARRAY_SIZE(msgs);
147 err = ioctl(adapter_fd, I2C_RDWR, &data);
149 if (err < 0) {
150 fprintf(stderr, "Unable to read Primary Link HDCP: %s\n",
151 strerror(errno));
152 return -1;
155 write_message = {
156 .addr = HDCP_PRIM_ADDR,
157 .len = 1,
158 .buf = &ksv_fifo_offset
160 read_message = {
161 .addr = HDCP_PRIM_ADDR,
162 .flags = I2C_M_RD,
163 .len = (__u16)((hdcp_prim[0x41] & 0x7f) * 5),
164 .buf = ksv_fifo
167 if (read_message.len) {
168 struct i2c_msg ksv_fifo_msgs[2] = { write_message, read_message };
170 data.msgs = ksv_fifo_msgs;
171 data.nmsgs = ARRAY_SIZE(msgs);
172 err = ioctl(adapter_fd, I2C_RDWR, &data);
173 if (err < 0) {
174 fprintf(stderr, "Unable to read KSV FIFO: %s\n",
175 strerror(errno));
176 return -1;
180 write_message = {
181 .addr = HDCP_SEC_ADDR,
182 .len = 1,
183 .buf = &offset
185 read_message = {
186 .addr = HDCP_SEC_ADDR,
187 .flags = I2C_M_RD,
188 .len = 256,
189 .buf = hdcp_sec
192 struct i2c_msg sec_msgs[2] = { write_message, read_message };
193 data.msgs = sec_msgs;
194 data.nmsgs = ARRAY_SIZE(msgs);
195 ioctl(adapter_fd, I2C_RDWR, &data);
197 return 0;
200 int read_hdcp(int adapter_fd)
202 __u8 hdcp_prim[256];
203 __u8 hdcp_sec[256];
204 __u8 ksv_fifo[128 * 5];
206 hdcp_prim[5] = 0xdd;
207 hdcp_sec[5] = 0xdd;
208 if (read_hdcp_registers(adapter_fd, hdcp_prim, hdcp_sec, ksv_fifo))
209 return -1;
210 printf("HDCP Primary Link Hex Dump:\n\n");
211 hex_block("", hdcp_prim, 128, false);
212 printf("\n");
213 hex_block("", hdcp_prim + 128, 128, false);
214 printf("\n");
215 if (hdcp_sec[5] != 0xdd) {
216 printf("HDCP Secondary Link Hex Dump:\n\n");
217 hex_block("", hdcp_sec, 128, false);
218 printf("\n");
219 hex_block("", hdcp_sec + 128, 128, false);
220 printf("\n");
222 printf("HDCP Primary Link:\n\n");
223 printf("Bksv: %02x %02x %02x %02x %02x\n",
224 hdcp_prim[0], hdcp_prim[1], hdcp_prim[2], hdcp_prim[3], hdcp_prim[4]);
225 printf("Ri': %02x %02x\n", hdcp_prim[9], hdcp_prim[8]);
226 printf("Pj': %02x\n", hdcp_prim[0x0a]);
227 printf("Aksv: %02x %02x %02x %02x %02x\n",
228 hdcp_prim[0x10], hdcp_prim[0x11], hdcp_prim[0x12], hdcp_prim[0x13], hdcp_prim[0x14]);
229 printf("Ainfo: %02x\n", hdcp_prim[0x15]);
230 printf("An: %02x %02x %02x %02x %02x %02x %02x %02x\n",
231 hdcp_prim[0x18], hdcp_prim[0x19], hdcp_prim[0x1a], hdcp_prim[0x1b],
232 hdcp_prim[0x1c], hdcp_prim[0x1d], hdcp_prim[0x1e], hdcp_prim[0x1f]);
233 printf("V'.H0: %02x %02x %02x %02x\n",
234 hdcp_prim[0x20], hdcp_prim[0x21], hdcp_prim[0x22], hdcp_prim[0x23]);
235 printf("V'.H1: %02x %02x %02x %02x\n",
236 hdcp_prim[0x24], hdcp_prim[0x25], hdcp_prim[0x26], hdcp_prim[0x27]);
237 printf("V'.H2: %02x %02x %02x %02x\n",
238 hdcp_prim[0x28], hdcp_prim[0x29], hdcp_prim[0x2a], hdcp_prim[0x2b]);
239 printf("V'.H3: %02x %02x %02x %02x\n",
240 hdcp_prim[0x2c], hdcp_prim[0x2d], hdcp_prim[0x2e], hdcp_prim[0x2f]);
241 printf("V'.H4: %02x %02x %02x %02x\n",
242 hdcp_prim[0x30], hdcp_prim[0x31], hdcp_prim[0x32], hdcp_prim[0x33]);
243 __u8 v = hdcp_prim[0x40];
244 printf("Bcaps: %02x\n", v);
245 if (v & 0x01)
246 printf("\tFAST_REAUTHENTICATION\n");
247 if (v & 0x02)
248 printf("\t1.1_FEATURES\n");
249 if (v & 0x10)
250 printf("\tFAST\n");
251 if (v & 0x20)
252 printf("\tREADY\n");
253 if (v & 0x40)
254 printf("\tREPEATER\n");
255 __u16 vv = hdcp_prim[0x41] | (hdcp_prim[0x42] << 8);
256 printf("Bstatus: %04x\n", vv);
257 printf("\tDEVICE_COUNT: %u\n", vv & 0x7f);
258 if (vv & 0x80)
259 printf("\tMAX_DEVS_EXCEEDED\n");
260 printf("\tDEPTH: %u\n", (vv >> 8) & 0x07);
261 if (vv & 0x800)
262 printf("\tMAX_CASCADE_EXCEEDED\n");
263 if (vv & 0x1000)
264 printf("\tHDMI_MODE\n");
265 if (vv & 0x7f) {
266 printf("KSV FIFO:\n");
267 for (unsigned i = 0; i < (vv & 0x7f); i++)
268 printf("\t%03u: %02x %02x %02x %02x %02x\n", i,
269 ksv_fifo[i * 5], ksv_fifo[i * 5 + 1],
270 ksv_fifo[i * 5 + 2], ksv_fifo[i * 5 + 3],
271 ksv_fifo[i * 5 + 4]);
273 v = hdcp_prim[0x50];
274 printf("HDCP2Version: %02x\n", v);
275 if (v & 4)
276 printf("\tHDCP2.2\n");
277 vv = hdcp_prim[0x70] | (hdcp_prim[0x71] << 8);
278 printf("RxStatus: %04x\n", vv);
279 if (vv & 0x3ff)
280 printf("\tMessage_Size: %u\n", vv & 0x3ff);
281 if (vv & 0x400)
282 printf("\tREADY\n");
283 if (vv & 0x800)
284 printf("\tREAUTH_REQ\n");
286 if (hdcp_sec[5] == 0xdd)
287 return 0;
289 printf("HDCP Secondary Link:\n\n");
290 printf("Bksv: %02x %02x %02x %02x %02x\n",
291 hdcp_sec[0], hdcp_sec[1], hdcp_sec[2], hdcp_sec[3], hdcp_sec[4]);
292 printf("Ri': %02x %02x\n", hdcp_sec[9], hdcp_sec[9]);
293 printf("Pj': %02x\n", hdcp_sec[0x0a]);
294 printf("Aksv: %02x %02x %02x %02x %02x\n",
295 hdcp_sec[0x10], hdcp_sec[0x11], hdcp_sec[0x12], hdcp_sec[0x13], hdcp_sec[0x14]);
296 printf("Ainfo: %02x\n", hdcp_sec[0x15]);
297 printf("An: %02x %02x %02x %02x %02x %02x %02x %02x\n",
298 hdcp_sec[0x18], hdcp_sec[0x19], hdcp_sec[0x1a], hdcp_sec[0x1b],
299 hdcp_sec[0x1c], hdcp_sec[0x1d], hdcp_sec[0x1e], hdcp_sec[0x1f]);
300 return 0;
303 static int read_hdcp_ri_register(int adapter_fd, __u16 *v)
305 struct i2c_rdwr_ioctl_data data;
306 struct i2c_msg write_message;
307 struct i2c_msg read_message;
308 __u8 ri[2];
309 __u8 offset = 8;
310 int err;
312 write_message = {
313 .addr = HDCP_PRIM_ADDR,
314 .len = 1,
315 .buf = &offset
317 read_message = {
318 .addr = HDCP_PRIM_ADDR,
319 .flags = I2C_M_RD,
320 .len = 2,
321 .buf = ri
324 struct i2c_msg msgs[2] = { write_message, read_message };
326 data.msgs = msgs;
327 data.nmsgs = ARRAY_SIZE(msgs);
328 err = ioctl(adapter_fd, I2C_RDWR, &data);
330 if (err < 0)
331 fprintf(stderr, "Unable to read Ri: %s\n", strerror(errno));
332 else
333 *v = ri[1] << 8 | ri[0];
335 return err < 0 ? err : 0;
338 int read_hdcp_ri(int adapter_fd, double ri_time)
340 __u16 ri;
342 while (1) {
343 if (!read_hdcp_ri_register(adapter_fd, &ri))
344 printf("Ri': %04x\n", ri);
345 usleep(ri_time * 1000000);
347 return 0;
350 #endif