drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / drivers / media / cec / usb / extron-da-hd-4k-plus / extron-da-hd-4k-plus.c
blob8526f613a40ef45878458f5d080890dc6d209c09
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright 2021-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4 */
6 /*
7 * Currently this driver does not fully support the serial port of the
8 * Extron, only the USB port is fully supported.
10 * Issues specific to using the serial port instead of the USB since the
11 * serial port doesn't detect if the device is powered off:
13 * - Some periodic ping mechanism is needed to detect when the Extron is
14 * powered off and when it is powered on again.
15 * - What to do when it is powered off and the driver is modprobed? Keep
16 * trying to contact the Extron indefinitely?
19 #include <linux/completion.h>
20 #include <linux/ctype.h>
21 #include <linux/delay.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/time.h>
29 #include "extron-da-hd-4k-plus.h"
31 MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
32 MODULE_DESCRIPTION("Extron DA HD 4K PLUS HDMI CEC driver");
33 MODULE_LICENSE("GPL");
35 static int debug;
36 module_param(debug, int, 0644);
37 MODULE_PARM_DESC(debug, "debug level (0-1)");
39 static unsigned int vendor_id;
40 module_param(vendor_id, uint, 0444);
41 MODULE_PARM_DESC(vendor_id, "CEC Vendor ID");
43 static char manufacturer_name[4];
44 module_param_string(manufacturer_name, manufacturer_name,
45 sizeof(manufacturer_name), 0644);
46 MODULE_PARM_DESC(manufacturer_name,
47 "EDID Vendor String (3 uppercase characters)");
49 static bool hpd_never_low;
50 module_param(hpd_never_low, bool, 0644);
51 MODULE_PARM_DESC(hpd_never_low, "Input HPD will never go low (1), or go low if all output HPDs are low (0, default)");
53 #define EXTRON_TIMEOUT_SECS 6
55 static const u8 hdmi_edid[256] = {
56 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
57 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x01, 0x20, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
59 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
60 0x0f, 0x50, 0x54, 0x20, 0x00, 0x00, 0x01, 0x01,
61 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
62 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
63 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
64 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
65 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
66 0x87, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
67 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
68 0x64, 0x6d, 0x69, 0x2d, 0x31, 0x30, 0x38, 0x30,
69 0x70, 0x36, 0x30, 0x0a, 0x00, 0x00, 0x00, 0xfe,
70 0x00, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x0a, 0x20,
71 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x95,
73 0x02, 0x03, 0x1b, 0xf1, 0x42, 0x10, 0x01, 0x23,
74 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x68,
75 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00, 0x21, 0x01,
76 0xe2, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89,
91 static const u8 hdmi_edid_4k_300[256] = {
92 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
93 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x01, 0x20, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
95 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
96 0x0f, 0x50, 0x54, 0x20, 0x00, 0x00, 0x01, 0x01,
97 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
98 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
99 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
100 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
101 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
102 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
103 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
104 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x36,
105 0x30, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0xfe,
106 0x00, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x0a, 0x20,
107 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x87,
109 0x02, 0x03, 0x1f, 0xf1, 0x43, 0x10, 0x5f, 0x01,
110 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00,
111 0x6b, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c,
112 0x21, 0x00, 0x20, 0x01, 0xe2, 0x00, 0xca, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6,
127 static const u8 hdmi_edid_4k_600[256] = {
128 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
129 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x01, 0x20, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
131 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26,
132 0x0f, 0x50, 0x54, 0x20, 0x00, 0x00, 0x01, 0x01,
133 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
134 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8,
135 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58,
136 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
137 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
138 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
139 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68,
140 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x36,
141 0x30, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0xfe,
142 0x00, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x0a, 0x20,
143 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x4c,
145 0x02, 0x03, 0x28, 0xf1, 0x44, 0x61, 0x5f, 0x10,
146 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00,
147 0x00, 0x6b, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00,
148 0x3c, 0x21, 0x00, 0x20, 0x01, 0x67, 0xd8, 0x5d,
149 0xc4, 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xca,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82,
163 static int extron_send_byte(struct serio *serio, char byte)
165 int err, i;
167 for (i = 0; i < 100; i++) {
168 err = serio_write(serio, byte);
169 if (!err)
170 break;
171 usleep_range(80, 120);
173 if (err)
174 dev_warn(&serio->dev, "unable to write byte after 100 attempts\n");
175 return err ? -EIO : 0;
178 static int extron_send_len(struct serio *serio, const char *command,
179 const unsigned char *bin, unsigned int len)
181 int err = 0;
183 for (; !err && *command; command++)
184 err = extron_send_byte(serio, *command);
185 if (!err)
186 err = extron_send_byte(serio, '\r');
187 if (bin)
188 for (; !err && len; len--)
189 err = extron_send_byte(serio, *bin++);
190 return err;
193 static int extron_send_and_wait_len(struct extron *extron, struct extron_port *port,
194 const char *cmd, const unsigned char *bin,
195 unsigned int len, const char *response)
197 int timeout = EXTRON_TIMEOUT_SECS * HZ;
198 int err;
200 if (debug) {
201 if (response)
202 dev_info(extron->dev, "transmit %s (response: %s)\n",
203 cmd, response);
204 else
205 dev_info(extron->dev, "transmit %s\n", cmd);
208 mutex_lock(&extron->serio_lock);
209 if (port) {
210 init_completion(&port->cmd_done);
211 port->cmd_error = 0;
212 port->response = response;
213 } else {
214 init_completion(&extron->cmd_done);
215 extron->cmd_error = 0;
216 extron->response = response;
218 err = extron_send_len(extron->serio, cmd, bin, len);
220 if (!err && response &&
221 !wait_for_completion_timeout(port ? &port->cmd_done : &extron->cmd_done, timeout)) {
222 dev_info(extron->dev, "transmit %s failed with %s (expected: %s)\n",
223 cmd, extron->reply, response);
224 err = -ETIMEDOUT;
227 if (!err && response && (port ? port->cmd_error : extron->cmd_error)) {
228 dev_info(extron->dev, "transmit %s failed with E%02u (expected: %s)\n",
229 cmd, port ? port->cmd_error : extron->cmd_error, response);
230 if (port)
231 port->cmd_error = 0;
232 else
233 extron->cmd_error = 0;
234 err = -EPROTO;
236 if (port)
237 port->response = NULL;
238 else
239 extron->response = NULL;
240 mutex_unlock(&extron->serio_lock);
241 return err;
244 static int extron_send_and_wait(struct extron *extron, struct extron_port *port,
245 const char *cmd, const char *response)
247 return extron_send_and_wait_len(extron, port, cmd, NULL, 0, response);
250 static void extron_parse_edid(struct extron_port *port)
252 const u8 *edid = port->edid;
253 unsigned int i, end;
254 u8 d;
256 port->has_4kp30 = false;
257 port->has_4kp60 = false;
258 port->has_qy = false;
259 port->has_qs = false;
260 /* Store Established Timings 1 and 2 */
261 port->est_i = edid[0x23];
262 port->est_ii = edid[0x24];
264 // Check DTDs in base block
265 for (i = 0; i < 4; i++) {
266 const u8 *dtd = edid + 0x36 + i * 18;
267 unsigned int w, h;
268 unsigned int mhz;
269 u64 pclk;
271 if (!dtd[0] && !dtd[1])
272 continue;
273 w = dtd[2] + ((dtd[4] & 0xf0) << 4);
274 h = dtd[5] + ((dtd[7] & 0xf0) << 4);
275 if (w != 3840 || h != 2160)
276 continue;
278 w += dtd[3] + ((dtd[4] & 0x0f) << 8);
279 h += dtd[6] + ((dtd[7] & 0x0f) << 8);
280 pclk = dtd[0] + (dtd[1] << 8);
281 pclk *= 100000;
282 mhz = div_u64(pclk, w * h);
283 if (mhz >= 297)
284 port->has_4kp30 = true;
285 if (mhz >= 594)
286 port->has_4kp60 = true;
289 if (port->edid_blocks == 1)
290 return;
292 edid += 128;
294 /* Return if not a CTA-861 extension block */
295 if (edid[0] != 0x02 || edid[1] != 0x03)
296 return;
298 /* search Video Data Block (tag 2) */
299 d = edid[2] & 0x7f;
300 /* Check if there are Data Blocks */
301 if (d <= 4)
302 return;
304 i = 4;
305 end = d;
307 do {
308 u8 tag = edid[i] >> 5;
309 u8 len = edid[i] & 0x1f;
311 /* Avoid buffer overrun in case the EDID is malformed */
312 if (i + len + 1 > 0x7f)
313 return;
315 switch (tag) {
316 case 2: /* Video Data Block */
317 /* Search for VIC 97 */
318 if (memchr(edid + i + 1, 97, len))
319 port->has_4kp60 = true;
320 /* Search for VIC 95 */
321 if (memchr(edid + i + 1, 95, len))
322 port->has_4kp30 = true;
323 break;
325 case 7: /* Use Extended Tag */
326 switch (edid[i + 1]) {
327 case 0: /* Video Capability Data Block */
328 if (edid[i + 2] & 0x80)
329 port->has_qy = true;
330 if (edid[i + 2] & 0x40)
331 port->has_qs = true;
332 break;
334 break;
336 i += len + 1;
337 } while (i < end);
340 static int get_edid_tag_location(const u8 *edid, unsigned int size,
341 u8 want_tag, u8 ext_tag)
343 unsigned int offset = 128;
344 int i, end;
345 u8 d;
347 edid += offset;
349 /* Return if not a CTA-861 extension block */
350 if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03)
351 return -1;
353 /* search tag */
354 d = edid[0x02] & 0x7f;
355 if (d <= 4)
356 return -1;
358 i = 0x04;
359 end = 0x00 + d;
361 do {
362 unsigned char tag = edid[i] >> 5;
363 unsigned char len = edid[i] & 0x1f;
365 if (tag != want_tag || i + len > end) {
366 i += len + 1;
367 continue;
370 if (tag < 7 || (len >= 1 && edid[i + 1] == ext_tag))
371 return offset + i;
372 i += len + 1;
373 } while (i < end);
374 return -1;
377 static void extron_edid_crc(u8 *edid)
379 u8 sum = 0;
380 int offset;
382 /* Update CRC */
383 for (offset = 0; offset < 127; offset++)
384 sum += edid[offset];
385 edid[127] = 256 - sum;
389 * Fill in EDID string. As per VESA EDID-1.3, strings are at most 13 chars
390 * long. If shorter then add a 0x0a character after the string and pad the
391 * remainder with spaces.
393 static void extron_set_edid_string(u8 *start, const char *s)
395 const unsigned int max_len = 13;
396 int len = strlen(s);
398 memset(start, ' ', max_len);
399 if (len > max_len)
400 len = max_len;
401 memcpy(start, s, len);
402 if (len < max_len)
403 start[len] = 0x0a;
406 static void extron_update_edid(struct extron_port *port, unsigned int blocks)
408 int offset;
409 u8 c1, c2;
411 c1 = ((manufacturer_name[0] - '@') << 2) |
412 (((manufacturer_name[1] - '@') >> 3) & 0x03);
413 c2 = (((manufacturer_name[1] - '@') & 0x07) << 5) |
414 ((manufacturer_name[2] - '@') & 0x1f);
416 port->edid_tmp[8] = c1;
417 port->edid_tmp[9] = c2;
419 /* Set Established Timings, but always enable VGA */
420 port->edid_tmp[0x23] = port->est_i | 0x20;
421 port->edid_tmp[0x24] = port->est_ii;
423 /* Set the Monitor Name to the unit name */
424 extron_set_edid_string(port->edid_tmp + 0x5f, port->extron->unit_name);
425 /* Set the ASCII String to the CEC adapter name */
426 extron_set_edid_string(port->edid_tmp + 0x71, port->adap->name);
428 extron_edid_crc(port->edid_tmp);
430 /* Find Video Capability Data Block */
431 offset = get_edid_tag_location(port->edid_tmp, blocks * 128, 7, 0);
432 if (offset > 0) {
433 port->edid_tmp[offset + 2] &= ~0xc0;
434 if (port->has_qy)
435 port->edid_tmp[offset + 2] |= 0x80;
436 if (port->has_qs)
437 port->edid_tmp[offset + 2] |= 0x40;
440 extron_edid_crc(port->edid_tmp + 128);
443 static int extron_write_edid(struct extron_port *port,
444 const u8 *edid, unsigned int blocks)
446 struct extron *extron = port->extron;
447 u16 phys_addr = CEC_PHYS_ADDR_INVALID;
448 int ret;
450 if (cec_get_edid_spa_location(edid, blocks * 128))
451 phys_addr = 0;
453 if (mutex_lock_interruptible(&extron->edid_lock))
454 return -EINTR;
456 memcpy(port->edid_tmp, edid, blocks * 128);
458 if (manufacturer_name[0])
459 extron_update_edid(port, blocks);
461 ret = extron_send_and_wait_len(port->extron, port, "W+UF256,in.bin",
462 port->edid_tmp, sizeof(port->edid_tmp),
463 "Upl");
464 if (ret)
465 goto unlock;
466 ret = extron_send_and_wait(port->extron, port, "WI1,in.binEDID",
467 "EdidI01");
468 if (ret)
469 goto unlock;
471 port->edid_blocks = blocks;
472 memcpy(port->edid, port->edid_tmp, blocks * 128);
473 port->read_edid = true;
474 mutex_unlock(&extron->edid_lock);
476 cec_s_phys_addr(port->adap, phys_addr, false);
477 return 0;
479 unlock:
480 mutex_unlock(&extron->edid_lock);
481 return ret;
484 static void update_edid_work(struct work_struct *w)
486 struct extron *extron = container_of(w, struct extron,
487 work_update_edid.work);
488 struct extron_port *in = extron->ports[extron->num_out_ports];
489 struct extron_port *p;
490 bool has_edid = false;
491 bool has_4kp30 = true;
492 bool has_4kp60 = true;
493 bool has_qy = true;
494 bool has_qs = true;
495 u8 est_i = 0xff;
496 u8 est_ii = 0xff;
497 unsigned int out;
499 for (out = 0; has_4kp60 && out < extron->num_out_ports; out++) {
500 p = extron->ports[out];
501 if (p->read_edid) {
502 has_4kp60 = p->has_4kp60;
503 est_i &= p->est_i;
504 est_ii &= p->est_ii;
505 has_edid = true;
508 for (out = 0; has_4kp30 && out < extron->num_out_ports; out++)
509 if (extron->ports[out]->read_edid)
510 has_4kp30 = extron->ports[out]->has_4kp30;
512 for (out = 0; has_qy && out < extron->num_out_ports; out++)
513 if (extron->ports[out]->read_edid)
514 has_qy = extron->ports[out]->has_qy;
516 for (out = 0; has_qs && out < extron->num_out_ports; out++)
517 if (extron->ports[out]->read_edid)
518 has_qs = extron->ports[out]->has_qs;
520 /* exit if no output port had an EDID */
521 if (!has_edid)
522 return;
524 /* exit if the input EDID properties remained unchanged */
525 if (has_4kp60 == in->has_4kp60 && has_4kp30 == in->has_4kp30 &&
526 has_qy == in->has_qy && has_qs == in->has_qs &&
527 est_i == in->est_i && est_ii == in->est_ii)
528 return;
530 in->has_4kp60 = has_4kp60;
531 in->has_4kp30 = has_4kp30;
532 in->has_qy = has_qy;
533 in->has_qs = has_qs;
534 in->est_i = est_i;
535 in->est_ii = est_ii;
536 extron_write_edid(extron->ports[extron->num_out_ports],
537 has_4kp60 ? hdmi_edid_4k_600 :
538 (has_4kp30 ? hdmi_edid_4k_300 : hdmi_edid), 2);
541 static void extron_read_edid(struct extron_port *port)
543 struct extron *extron = port->extron;
544 char cmd[10], reply[10];
545 unsigned int idx;
547 idx = port->port.port + (port->is_input ? 0 : extron->num_in_ports);
548 snprintf(cmd, sizeof(cmd), "WR%uEDID", idx);
549 snprintf(reply, sizeof(reply), "EdidR%u", idx);
550 if (mutex_lock_interruptible(&extron->edid_lock))
551 return;
552 if (port->read_edid)
553 goto unlock;
554 extron->edid_bytes_read = 0;
555 extron->edid_port = port;
556 port->edid_blocks = 0;
557 if (!port->has_edid)
558 goto no_edid;
560 extron->edid_reading = true;
562 if (!extron_send_and_wait(extron, port, cmd, reply))
563 wait_for_completion_killable_timeout(&extron->edid_completion,
564 msecs_to_jiffies(1000));
565 if (port->edid_blocks) {
566 extron_parse_edid(port);
567 port->read_edid = true;
568 if (!port->is_input)
569 v4l2_ctrl_s_ctrl(port->ctrl_tx_edid_present, 1);
571 no_edid:
572 extron->edid_reading = false;
573 unlock:
574 mutex_unlock(&extron->edid_lock);
575 cancel_delayed_work_sync(&extron->work_update_edid);
576 if (manufacturer_name[0])
577 schedule_delayed_work(&extron->work_update_edid,
578 msecs_to_jiffies(1000));
581 static void extron_irq_work_handler(struct work_struct *work)
583 struct extron_port *port =
584 container_of(work, struct extron_port, irq_work);
585 struct extron *extron = port->extron;
586 unsigned long flags;
587 bool update_pa;
588 u16 pa;
589 bool update_has_signal;
590 bool has_signal;
591 bool update_has_edid;
592 bool has_edid;
593 u32 status;
595 spin_lock_irqsave(&port->msg_lock, flags);
596 while (port->rx_msg_num) {
597 spin_unlock_irqrestore(&port->msg_lock, flags);
598 cec_received_msg(port->adap,
599 &port->rx_msg[port->rx_msg_cur_idx]);
600 spin_lock_irqsave(&port->msg_lock, flags);
601 if (port->rx_msg_num)
602 port->rx_msg_num--;
603 port->rx_msg_cur_idx =
604 (port->rx_msg_cur_idx + 1) % NUM_MSGS;
606 update_pa = port->update_phys_addr;
607 pa = port->phys_addr;
608 port->update_phys_addr = false;
609 update_has_signal = port->update_has_signal;
610 has_signal = port->has_signal;
611 port->update_has_signal = false;
612 update_has_edid = port->update_has_edid;
613 has_edid = port->has_edid;
614 port->update_has_edid = false;
615 status = port->tx_done_status;
616 port->tx_done_status = 0;
617 spin_unlock_irqrestore(&port->msg_lock, flags);
619 if (status)
620 cec_transmit_done(port->adap, status, 0, 0, 0, 0);
622 if (update_has_signal && port->is_input)
623 v4l2_ctrl_s_ctrl(port->ctrl_rx_power_present, has_signal);
625 if (update_has_edid && !port->is_input) {
626 v4l2_ctrl_s_ctrl(port->ctrl_tx_hotplug,
627 port->has_edid);
628 if (port->has_edid) {
629 port->port.found_sink = true;
630 port->port.lost_sink_ts = ktime_set(0, 0);
631 } else {
632 port->port.lost_sink_ts = ktime_get();
634 if (!has_edid) {
635 port->edid_blocks = 0;
636 port->read_edid = false;
637 if (extron->edid_reading && !has_edid &&
638 extron->edid_port == port)
639 extron->edid_reading = false;
640 v4l2_ctrl_s_ctrl(port->ctrl_tx_edid_present, 0);
641 } else if (!extron->edid_reading || extron->edid_port != port) {
642 extron_read_edid(port);
645 if (update_pa)
646 cec_s_phys_addr(port->adap, pa, false);
649 static void extron_process_received(struct extron_port *port, const char *data)
651 struct cec_msg msg = {};
652 unsigned int len = strlen(data);
653 unsigned long irq_flags;
654 unsigned int idx;
656 if (!port || port->disconnected)
657 return;
659 if (len < 5 || (len - 2) % 3 || data[len - 2] != '*')
660 goto malformed;
662 while (*data != '*') {
663 int v = hex2bin(&msg.msg[msg.len], data + 1, 1);
665 if (*data != '%' || v)
666 goto malformed;
667 msg.len++;
668 data += 3;
671 spin_lock_irqsave(&port->msg_lock, irq_flags);
672 idx = (port->rx_msg_cur_idx + port->rx_msg_num) %
673 NUM_MSGS;
674 if (port->rx_msg_num == NUM_MSGS) {
675 dev_warn(port->dev,
676 "message queue is full, dropping %*ph\n",
677 msg.len, msg.msg);
678 spin_unlock_irqrestore(&port->msg_lock,
679 irq_flags);
680 return;
682 port->rx_msg_num++;
683 port->rx_msg[idx] = msg;
684 spin_unlock_irqrestore(&port->msg_lock, irq_flags);
685 if (!port->disconnected)
686 schedule_work(&port->irq_work);
687 return;
689 malformed:
690 dev_info(port->extron->dev, "malformed msg received: '%s'\n", data);
693 static void extron_port_signal_change(struct extron_port *port, bool has_sig)
695 unsigned long irq_flags;
696 bool update = false;
698 if (!port)
699 return;
701 spin_lock_irqsave(&port->msg_lock, irq_flags);
702 if (!port->update_has_signal && port->has_signal != has_sig) {
703 port->update_has_signal = true;
704 update = true;
706 port->has_signal = has_sig;
707 spin_unlock_irqrestore(&port->msg_lock, irq_flags);
708 if (update && !port->disconnected)
709 schedule_work(&port->irq_work);
712 static void extron_process_signal_change(struct extron *extron, const char *data)
714 unsigned int i;
716 extron_port_signal_change(extron->ports[extron->num_out_ports],
717 data[0] == '1');
718 for (i = 0; i < extron->num_out_ports; i++)
719 extron_port_signal_change(extron->ports[i],
720 data[2 + 2 * i] != '0');
723 static void extron_port_edid_change(struct extron_port *port, bool has_edid)
725 unsigned long irq_flags;
726 bool update = false;
728 if (!port)
729 return;
731 spin_lock_irqsave(&port->msg_lock, irq_flags);
732 if (!port->update_has_edid && port->has_edid != has_edid) {
733 port->update_has_edid = true;
734 update = true;
736 port->has_edid = has_edid;
737 spin_unlock_irqrestore(&port->msg_lock, irq_flags);
738 if (update && !port->disconnected)
739 schedule_work(&port->irq_work);
742 static void extron_process_edid_change(struct extron *extron, const char *data)
744 unsigned int i;
747 * Do nothing if the Extron isn't ready yet. Trying to do this
748 * while the Extron firmware is still settling will fail.
750 if (!extron->is_ready)
751 return;
753 for (i = 0; i < extron->num_out_ports; i++)
754 extron_port_edid_change(extron->ports[i],
755 data[2 + 2 * i] != '0');
758 static void extron_phys_addr_change(struct extron_port *port, u16 pa)
760 unsigned long irq_flags;
761 bool update = false;
763 if (!port)
764 return;
766 spin_lock_irqsave(&port->msg_lock, irq_flags);
767 if (!port->update_phys_addr && port->phys_addr != pa) {
768 update = true;
769 port->update_phys_addr = true;
771 port->phys_addr = pa;
772 spin_unlock_irqrestore(&port->msg_lock, irq_flags);
773 if (update && !port->disconnected)
774 schedule_work(&port->irq_work);
777 static void extron_process_tx_done(struct extron_port *port, char status)
779 unsigned long irq_flags;
780 unsigned int tx_status;
782 if (!port)
783 return;
785 switch (status) {
786 case '0':
787 tx_status = CEC_TX_STATUS_NACK | CEC_TX_STATUS_MAX_RETRIES;
788 break;
789 case '1':
790 tx_status = CEC_TX_STATUS_OK;
791 break;
792 default:
793 tx_status = CEC_TX_STATUS_ERROR;
794 break;
796 spin_lock_irqsave(&port->msg_lock, irq_flags);
797 port->tx_done_status = tx_status;
798 spin_unlock_irqrestore(&port->msg_lock, irq_flags);
799 if (!port->disconnected)
800 schedule_work(&port->irq_work);
803 static void extron_add_edid(struct extron_port *port, const char *hex)
805 struct extron *extron = port ? port->extron : NULL;
807 if (!port || port != extron->edid_port)
808 return;
809 while (extron->edid_bytes_read < sizeof(port->edid) && *hex) {
810 int err = hex2bin(&port->edid[extron->edid_bytes_read], hex, 1);
812 if (err) {
813 extron->edid_reading = false;
814 complete(&extron->edid_completion);
815 break;
817 extron->edid_bytes_read++;
818 hex += 2;
820 if (extron->edid_bytes_read == 128 &&
821 port->edid[126] == 0) {
822 /* There are no extension blocks, we're done */
823 port->edid_blocks = 1;
824 extron->edid_reading = false;
825 complete(&extron->edid_completion);
827 if (extron->edid_bytes_read < sizeof(port->edid))
828 return;
829 if (!*hex)
830 port->edid_blocks = 2;
831 extron->edid_reading = false;
832 complete(&extron->edid_completion);
835 static irqreturn_t extron_interrupt(struct serio *serio, unsigned char data,
836 unsigned int flags)
838 struct extron *extron = serio_get_drvdata(serio);
839 struct extron_port *port = NULL;
840 bool found_response;
841 unsigned int p;
843 if (data == '\r' || data == '\n') {
844 if (extron->idx == 0)
845 return IRQ_HANDLED;
846 memcpy(extron->data, extron->buf, extron->idx);
847 extron->len = extron->idx;
848 extron->data[extron->len] = 0;
849 if (debug)
850 dev_info(extron->dev, "received %s\n", extron->data);
851 extron->idx = 0;
852 if (!memcmp(extron->data, "Sig", 3) &&
853 extron->data[4] == '*') {
854 extron_process_signal_change(extron, extron->data + 3);
855 } else if (!memcmp(extron->data, "Hdcp", 4) &&
856 extron->data[5] == '*') {
857 extron_process_edid_change(extron, extron->data + 4);
858 } else if (!memcmp(extron->data, "DcecI", 5) &&
859 extron->data[5] >= '1' &&
860 extron->data[5] < '1' + extron->num_in_ports) {
861 unsigned int p = extron->data[5] - '1';
863 p += extron->num_out_ports;
864 extron_process_tx_done(extron->ports[p],
865 extron->data[extron->len - 1]);
866 } else if (!memcmp(extron->data, "Ceci", 4) &&
867 extron->data[4] >= '1' &&
868 extron->data[4] < '1' + extron->num_in_ports &&
869 extron->data[5] == '*') {
870 unsigned int p = extron->data[4] - '1';
872 p += extron->num_out_ports;
873 extron_process_received(extron->ports[p],
874 extron->data + 6);
875 } else if (!memcmp(extron->data, "DcecO", 5) &&
876 extron->data[5] >= '1' &&
877 extron->data[5] < '1' + extron->num_out_ports) {
878 unsigned int p = extron->data[5] - '1';
880 extron_process_tx_done(extron->ports[p],
881 extron->data[extron->len - 1]);
882 } else if (!memcmp(extron->data, "Ceco", 4) &&
883 extron->data[4] >= '1' &&
884 extron->data[4] < '1' + extron->num_out_ports &&
885 extron->data[5] == '*') {
886 unsigned int p = extron->data[4] - '1';
888 extron_process_received(extron->ports[p],
889 extron->data + 6);
890 } else if (!memcmp(extron->data, "Pceco", 5) &&
891 extron->data[5] >= '1' &&
892 extron->data[5] < '1' + extron->num_out_ports) {
893 unsigned int p = extron->data[5] - '1';
894 unsigned int tmp_pa[2] = { 0xff, 0xff };
896 if (sscanf(extron->data + 7, "%%%02x%%%02x",
897 &tmp_pa[0], &tmp_pa[1]) == 2)
898 extron_phys_addr_change(extron->ports[p],
899 tmp_pa[0] << 8 | tmp_pa[1]);
900 } else if (!memcmp(extron->data, "Pceci", 5) &&
901 extron->data[5] >= '1' &&
902 extron->data[5] < '1' + extron->num_in_ports) {
903 unsigned int p = extron->data[5] - '1';
904 unsigned int tmp_pa[2] = { 0xff, 0xff };
906 p += extron->num_out_ports;
907 if (sscanf(extron->data + 7, "%%%02x%%%02x",
908 &tmp_pa[0], &tmp_pa[1]) == 2)
909 extron_phys_addr_change(extron->ports[p],
910 tmp_pa[0] << 8 | tmp_pa[1]);
911 } else if (!memcmp(extron->data, "EdidR", 5) &&
912 extron->data[5] >= '1' &&
913 extron->data[5] < '1' + extron->num_ports &&
914 extron->data[6] == '*') {
915 unsigned int p = extron->data[5] - '1';
917 if (p)
918 p--;
919 else
920 p = extron->num_out_ports;
921 extron_add_edid(extron->ports[p], extron->data + 7);
922 } else if (extron->edid_reading && extron->len == 32 &&
923 extron->edid_port) {
924 extron_add_edid(extron->edid_port, extron->data);
927 found_response = false;
928 if (extron->response &&
929 !strncmp(extron->response, extron->data,
930 strlen(extron->response)))
931 found_response = true;
933 for (p = 0; !found_response && p < extron->num_ports; p++) {
934 port = extron->ports[p];
935 if (port && port->response &&
936 !strncmp(port->response, extron->data,
937 strlen(port->response)))
938 found_response = true;
941 if (!found_response && extron->response &&
942 extron->data[0] == 'E' &&
943 isdigit(extron->data[1]) &&
944 isdigit(extron->data[2]) &&
945 !extron->data[3]) {
946 extron->cmd_error = (extron->data[1] - '0') * 10 +
947 extron->data[2] - '0';
948 extron->response = NULL;
949 complete(&extron->cmd_done);
952 if (!found_response)
953 return IRQ_HANDLED;
955 memcpy(extron->reply, extron->data, extron->len);
956 extron->reply[extron->len] = 0;
957 if (!port) {
958 extron->response = NULL;
959 complete(&extron->cmd_done);
960 } else {
961 port->response = NULL;
962 complete(&port->cmd_done);
964 return IRQ_HANDLED;
967 if (extron->idx >= DATA_SIZE - 1) {
968 dev_info(extron->dev,
969 "throwing away %d bytes of garbage\n", extron->idx);
970 extron->idx = 0;
972 extron->buf[extron->idx++] = (char)data;
973 return IRQ_HANDLED;
976 static int extron_cec_adap_enable(struct cec_adapter *adap, bool enable)
978 struct extron_port *port = cec_get_drvdata(adap);
980 return (port->disconnected && enable) ? -ENODEV : 0;
983 static int extron_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
985 struct extron_port *port = cec_get_drvdata(adap);
986 char cmd[26];
987 char resp[25];
988 u8 la = log_addr == CEC_LOG_ADDR_INVALID ? 15 : log_addr;
989 int err;
991 if (port->disconnected)
992 return -ENODEV;
993 snprintf(cmd, sizeof(cmd), "W%c%u*%uLCEC",
994 port->direction, port->port.port, la);
995 snprintf(resp, sizeof(resp), "Lcec%c%u*%u",
996 port->direction, port->port.port, la);
997 err = extron_send_and_wait(port->extron, port, cmd, resp);
998 return log_addr != CEC_LOG_ADDR_INVALID && err ? err : 0;
1001 static int extron_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
1002 u32 signal_free_time, struct cec_msg *msg)
1004 struct extron_port *port = cec_get_drvdata(adap);
1005 char buf[CEC_MAX_MSG_SIZE * 3 + 1];
1006 char cmd[CEC_MAX_MSG_SIZE * 3 + 13];
1007 unsigned int i;
1009 if (port->disconnected)
1010 return -ENODEV;
1011 buf[0] = 0;
1012 for (i = 0; i < msg->len - 1; i++)
1013 sprintf(buf + i * 3, "%%%02X", msg->msg[i + 1]);
1014 snprintf(cmd, sizeof(cmd), "W%c%u*%u*%u*%sDCEC",
1015 port->direction, port->port.port,
1016 cec_msg_initiator(msg), cec_msg_destination(msg), buf);
1017 return extron_send_and_wait(port->extron, port, cmd, NULL);
1020 static void extron_cec_adap_unconfigured(struct cec_adapter *adap)
1022 struct extron_port *port = cec_get_drvdata(adap);
1024 if (port->disconnected)
1025 return;
1026 if (debug)
1027 dev_info(port->extron->dev, "unconfigured port %d (%s)\n",
1028 port->port.port,
1029 port->extron->splitter.is_standby ? "Off" : "On");
1030 if (!port->is_input)
1031 cec_splitter_unconfigured_output(&port->port);
1034 static void extron_cec_configured(struct cec_adapter *adap)
1036 struct extron_port *port = cec_get_drvdata(adap);
1038 if (port->disconnected)
1039 return;
1040 if (debug)
1041 dev_info(port->extron->dev, "configured port %d (%s)\n",
1042 port->port.port,
1043 port->extron->splitter.is_standby ? "Off" : "On");
1044 if (!port->is_input)
1045 cec_splitter_configured_output(&port->port);
1048 static void extron_cec_adap_nb_transmit_canceled(struct cec_adapter *adap,
1049 const struct cec_msg *msg)
1051 struct extron_port *port = cec_get_drvdata(adap);
1052 struct cec_adapter *input_adap;
1054 if (!vendor_id)
1055 return;
1056 if (port->disconnected || port->is_input)
1057 return;
1058 input_adap = port->extron->ports[port->extron->num_out_ports]->adap;
1059 cec_splitter_nb_transmit_canceled_output(&port->port, msg, input_adap);
1062 static int extron_received(struct cec_adapter *adap, struct cec_msg *msg)
1064 struct extron_port *port = cec_get_drvdata(adap);
1066 if (!vendor_id)
1067 return -ENOMSG;
1068 if (port->disconnected)
1069 return -ENOMSG;
1070 if (port->is_input)
1071 return cec_splitter_received_input(&port->port, msg);
1072 return cec_splitter_received_output(&port->port, msg,
1073 port->extron->ports[port->extron->num_out_ports]->adap);
1076 #define log_printf(adap, file, fmt, arg...) \
1077 do { \
1078 if (file) \
1079 seq_printf((file), fmt, ## arg); \
1080 else \
1081 pr_info("cec-%s: " fmt, (adap)->name, ## arg); \
1082 } while (0)
1084 static const char * const pwr_state[] = {
1085 "on",
1086 "standby",
1087 "to on",
1088 "to standby",
1091 static void extron_adap_status_port(struct extron_port *port, struct seq_file *file)
1093 struct cec_adapter *adap = port->adap;
1095 if (port->disconnected) {
1096 log_printf(adap, file,
1097 "\tport %u: disconnected\n", port->port.port);
1098 return;
1100 if (port->is_input)
1101 log_printf(adap, file,
1102 "\tport %u: %s signal, %s edid, %s 4kp30, %s 4kp60, %sQS/%sQY, is %s\n",
1103 port->port.port,
1104 port->has_signal ? "has" : "no",
1105 port->has_edid ? "has" : "no",
1106 port->has_4kp30 ? "has" : "no",
1107 port->has_4kp60 ? "has" : "no",
1108 port->has_qs ? "" : "no ",
1109 port->has_qy ? "" : "no ",
1110 !port->port.adap->is_configured ? "not configured" :
1111 pwr_state[port->extron->splitter.is_standby]);
1112 else
1113 log_printf(adap, file,
1114 "\tport %u: %s sink, %s signal, %s edid, %s 4kp30, %s 4kp60, %sQS/%sQY, is %sactive source, is %s\n",
1115 port->port.port,
1116 port->port.found_sink ? "found" : "no",
1117 port->has_signal ? "has" : "no",
1118 port->has_edid ? "has" : "no",
1119 port->has_4kp30 ? "has" : "no",
1120 port->has_4kp60 ? "has" : "no",
1121 port->has_qs ? "" : "no ",
1122 port->has_qy ? "" : "no ",
1123 port->port.is_active_source ? "" : "not ",
1124 !port->port.adap->is_configured ? "not configured" :
1125 pwr_state[port->port.power_status & 3]);
1126 if (port->port.out_give_device_power_status_seq)
1127 log_printf(adap, file,
1128 "\tport %u: querying power status (%u, %lldms)\n",
1129 port->port.port,
1130 port->port.out_give_device_power_status_seq & ~(1 << 31),
1131 ktime_ms_delta(ktime_get(),
1132 port->port.out_give_device_power_status_ts));
1133 if (port->port.out_request_current_latency_seq)
1134 log_printf(adap, file,
1135 "\tport %u: querying latency (%u, %lldms)\n",
1136 port->port.port,
1137 port->port.out_request_current_latency_seq & ~(1 << 31),
1138 ktime_ms_delta(ktime_get(),
1139 port->port.out_request_current_latency_ts));
1142 static void extron_adap_status(struct cec_adapter *adap, struct seq_file *file)
1144 struct extron_port *port = cec_get_drvdata(adap);
1145 struct extron *extron = port->extron;
1146 unsigned int i;
1148 log_printf(adap, file, "name: %s type: %s\n",
1149 extron->unit_name, extron->unit_type);
1150 log_printf(adap, file, "model: 60-160%c-01 (1 input, %u outputs)\n",
1151 '6' + extron->num_out_ports / 2, extron->num_out_ports);
1152 log_printf(adap, file, "firmware version: %s CEC engine version: %s\n",
1153 extron->unit_fw_version, extron->unit_cec_engine_version);
1154 if (extron->hpd_never_low)
1155 log_printf(adap, file, "always keep input HPD high\n");
1156 else
1157 log_printf(adap, file,
1158 "pull input HPD low if all output HPDs are low\n");
1159 if (vendor_id)
1160 log_printf(adap, file,
1161 "splitter vendor ID: 0x%06x\n", vendor_id);
1162 if (manufacturer_name[0])
1163 log_printf(adap, file, "splitter manufacturer name: %s\n",
1164 manufacturer_name);
1165 log_printf(adap, file, "splitter power status: %s\n",
1166 pwr_state[extron->splitter.is_standby]);
1167 log_printf(adap, file, "%s port: %d (%s)\n",
1168 port->is_input ? "input" : "output",
1169 port->port.port, port->name);
1170 log_printf(adap, file, "splitter input port:\n");
1171 extron_adap_status_port(extron->ports[extron->num_out_ports], file);
1173 log_printf(adap, file, "splitter output ports:\n");
1174 for (i = 0; i < extron->num_out_ports; i++)
1175 extron_adap_status_port(extron->ports[i], file);
1177 if (!port->has_edid || !port->read_edid)
1178 return;
1180 for (i = 0; i < port->edid_blocks * 128; i += 16) {
1181 if (i % 128 == 0)
1182 log_printf(adap, file, "\n");
1183 log_printf(adap, file, "EDID: %*ph\n", 16, port->edid + i);
1187 static const struct cec_adap_ops extron_cec_adap_ops = {
1188 .adap_enable = extron_cec_adap_enable,
1189 .adap_log_addr = extron_cec_adap_log_addr,
1190 .adap_transmit = extron_cec_adap_transmit,
1191 .adap_nb_transmit_canceled = extron_cec_adap_nb_transmit_canceled,
1192 .adap_unconfigured = extron_cec_adap_unconfigured,
1193 .adap_status = extron_adap_status,
1194 .configured = extron_cec_configured,
1195 .received = extron_received,
1198 static int extron_querycap(struct file *file, void *priv,
1199 struct v4l2_capability *cap)
1201 struct extron_port *port = video_drvdata(file);
1203 strscpy(cap->driver, "extron-da-hd-4k-plus-cec", sizeof(cap->driver));
1204 strscpy(cap->card, cap->driver, sizeof(cap->card));
1205 snprintf(cap->bus_info, sizeof(cap->bus_info), "serio:%s", port->name);
1206 return 0;
1209 static int extron_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
1211 struct extron_port *port = video_drvdata(file);
1213 if (inp->index)
1214 return -EINVAL;
1215 inp->type = V4L2_INPUT_TYPE_CAMERA;
1216 snprintf(inp->name, sizeof(inp->name), "HDMI IN %u", port->port.port);
1217 inp->status = v4l2_ctrl_g_ctrl(port->ctrl_rx_power_present) ?
1218 0 : V4L2_IN_ST_NO_SIGNAL;
1219 return 0;
1222 static int extron_g_input(struct file *file, void *priv, unsigned int *i)
1224 *i = 0;
1225 return 0;
1228 static int extron_s_input(struct file *file, void *priv, unsigned int i)
1230 return i ? -EINVAL : 0;
1233 static int extron_enum_output(struct file *file, void *priv, struct v4l2_output *out)
1235 struct extron_port *port = video_drvdata(file);
1237 if (out->index)
1238 return -EINVAL;
1239 out->type = V4L2_OUTPUT_TYPE_ANALOG;
1240 snprintf(out->name, sizeof(out->name), "HDMI OUT %u", port->port.port);
1241 return 0;
1244 static int extron_g_output(struct file *file, void *priv, unsigned int *o)
1246 *o = 0;
1247 return 0;
1250 static int extron_s_output(struct file *file, void *priv, unsigned int o)
1252 return o ? -EINVAL : 0;
1255 static int extron_g_edid(struct file *file, void *_fh,
1256 struct v4l2_edid *edid)
1258 struct extron_port *port = video_drvdata(file);
1260 memset(edid->reserved, 0, sizeof(edid->reserved));
1261 if (port->disconnected)
1262 return -ENODEV;
1263 if (edid->pad)
1264 return -EINVAL;
1265 if (!port->has_edid)
1266 return -ENODATA;
1267 if (!port->read_edid)
1268 extron_read_edid(port);
1269 if (!port->read_edid)
1270 return -ENODATA;
1271 if (edid->start_block == 0 && edid->blocks == 0) {
1272 edid->blocks = port->edid_blocks;
1273 return 0;
1275 if (edid->start_block >= port->edid_blocks)
1276 return -EINVAL;
1277 if (edid->blocks > port->edid_blocks - edid->start_block)
1278 edid->blocks = port->edid_blocks - edid->start_block;
1279 memcpy(edid->edid, port->edid + edid->start_block * 128, edid->blocks * 128);
1280 return 0;
1283 static int extron_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid)
1285 struct extron_port *port = video_drvdata(file);
1287 memset(edid->reserved, 0, sizeof(edid->reserved));
1288 if (port->disconnected)
1289 return -ENODEV;
1290 if (edid->pad)
1291 return -EINVAL;
1293 /* Unfortunately it is not possible to clear the EDID */
1294 if (edid->blocks == 0)
1295 return -EINVAL;
1297 if (edid->blocks > MAX_EDID_BLOCKS) {
1298 edid->blocks = MAX_EDID_BLOCKS;
1299 return -E2BIG;
1302 if (cec_get_edid_spa_location(edid->edid, edid->blocks * 128))
1303 v4l2_set_edid_phys_addr(edid->edid, edid->blocks * 128, 0);
1304 extron_parse_edid(port);
1305 return extron_write_edid(port, edid->edid, edid->blocks);
1308 static int extron_log_status(struct file *file, void *priv)
1310 struct extron_port *port = video_drvdata(file);
1312 extron_adap_status(port->adap, NULL);
1313 return v4l2_ctrl_log_status(file, priv);
1316 static const struct v4l2_ioctl_ops extron_ioctl_ops = {
1317 .vidioc_querycap = extron_querycap,
1318 .vidioc_enum_input = extron_enum_input,
1319 .vidioc_g_input = extron_g_input,
1320 .vidioc_s_input = extron_s_input,
1321 .vidioc_enum_output = extron_enum_output,
1322 .vidioc_g_output = extron_g_output,
1323 .vidioc_s_output = extron_s_output,
1324 .vidioc_g_edid = extron_g_edid,
1325 .vidioc_s_edid = extron_s_edid,
1326 .vidioc_log_status = extron_log_status,
1327 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1328 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1331 static const struct v4l2_file_operations extron_fops = {
1332 .owner = THIS_MODULE,
1333 .open = v4l2_fh_open,
1334 .release = v4l2_fh_release,
1335 .poll = v4l2_ctrl_poll,
1336 .unlocked_ioctl = video_ioctl2,
1339 static const struct video_device extron_videodev = {
1340 .name = "extron-da-hd-4k-plus-cec",
1341 .vfl_dir = VFL_DIR_RX,
1342 .fops = &extron_fops,
1343 .ioctl_ops = &extron_ioctl_ops,
1344 .minor = -1,
1345 .release = video_device_release_empty,
1348 static void extron_disconnect(struct serio *serio)
1350 struct extron *extron = serio_get_drvdata(serio);
1351 unsigned int p;
1353 kthread_stop(extron->kthread_setup);
1355 for (p = 0; p < extron->num_ports; p++) {
1356 struct extron_port *port = extron->ports[p];
1358 if (!port)
1359 continue;
1360 port->disconnected = true;
1361 cancel_work_sync(&port->irq_work);
1363 cancel_delayed_work_sync(&extron->work_update_edid);
1364 for (p = 0; p < extron->num_ports; p++) {
1365 struct extron_port *port = extron->ports[p];
1367 if (!port)
1368 continue;
1370 if (port->cec_was_registered) {
1371 if (cec_is_registered(port->adap))
1372 cec_unregister_adapter(port->adap);
1374 * After registering the adapter, the
1375 * extron_setup_thread() function took an extra
1376 * reference to the device. We call the corresponding
1377 * put here.
1379 cec_put_device(port->adap);
1380 } else {
1381 cec_delete_adapter(port->adap);
1383 video_unregister_device(&port->vdev);
1386 complete(&extron->edid_completion);
1388 for (p = 0; p < extron->num_ports; p++) {
1389 struct extron_port *port = extron->ports[p];
1391 if (!port)
1392 continue;
1393 v4l2_ctrl_handler_free(&port->hdl);
1394 mutex_destroy(&port->video_lock);
1395 kfree(port);
1397 mutex_destroy(&extron->edid_lock);
1398 mutex_destroy(&extron->serio_lock);
1399 extron->serio = NULL;
1400 serio_set_drvdata(serio, NULL);
1401 serio_close(serio);
1404 static int extron_setup(struct extron *extron)
1406 struct serio *serio = extron->serio;
1407 struct extron_port *port;
1408 u8 *reply = extron->reply;
1409 unsigned int p;
1410 unsigned int major, minor;
1411 int err;
1414 * Attempt to disable CEC: avoid received CEC messages
1415 * from interfering with the other serial port traffic.
1417 extron_send_and_wait(extron, NULL, "WI1*0CCEC", NULL);
1418 extron_send_and_wait(extron, NULL, "WO0*CCEC", NULL);
1420 /* Obtain unit part number */
1421 err = extron_send_and_wait(extron, NULL, "N", "Pno");
1422 if (err)
1423 return err;
1424 dev_info(extron->dev, "Unit part number: %s\n", reply + 3);
1425 if (strcmp(reply + 3, "60-1607-01") &&
1426 strcmp(reply + 3, "60-1608-01") &&
1427 strcmp(reply + 3, "60-1609-01")) {
1428 dev_err(extron->dev, "Unsupported model\n");
1429 return -ENODEV;
1431 /* Up to 6 output ports and one input port */
1432 extron->num_out_ports = 2 * (reply[9] - '6');
1433 extron->splitter.num_out_ports = extron->num_out_ports;
1434 extron->splitter.ports = extron->splitter_ports;
1435 extron->splitter.dev = extron->dev;
1436 extron->num_in_ports = 1;
1437 extron->num_ports = extron->num_out_ports + extron->num_in_ports;
1438 dev_info(extron->dev, "Unit output ports: %d\n", extron->num_out_ports);
1439 dev_info(extron->dev, "Unit input ports: %d\n", extron->num_in_ports);
1441 err = extron_send_and_wait(extron, NULL, "W CN", "Ipn ");
1442 if (err)
1443 return err;
1444 dev_info(extron->dev, "Unit name: %s\n", reply + 4);
1445 strscpy(extron->unit_name, reply + 4, sizeof(extron->unit_name));
1447 err = extron_send_and_wait(extron, NULL, "*Q", "Bld");
1448 if (err)
1449 return err;
1450 dev_info(extron->dev, "Unit FW Version: %s\n", reply + 3);
1451 strscpy(extron->unit_fw_version, reply + 3,
1452 sizeof(extron->unit_fw_version));
1453 if (sscanf(reply + 3, "%u.%u.", &major, &minor) < 2 ||
1454 major < 1 || minor < 2) {
1455 dev_err(extron->dev,
1456 "Unsupported FW version (only 1.02 or up is supported)\n");
1457 return -ENODEV;
1460 err = extron_send_and_wait(extron, NULL, "2i", "Inf02*");
1461 if (err)
1462 return err;
1463 dev_info(extron->dev, "Unit Type: %s\n", reply + 6);
1464 strscpy(extron->unit_type, reply + 6, sizeof(extron->unit_type));
1466 err = extron_send_and_wait(extron, NULL, "39Q", "Ver39*");
1467 if (err)
1468 return err;
1469 dev_info(extron->dev, "CEC Engine Version: %s\n", reply + 6);
1470 strscpy(extron->unit_cec_engine_version, reply + 6,
1471 sizeof(extron->unit_cec_engine_version));
1473 /* Disable CEC */
1474 err = extron_send_and_wait(extron, NULL, "WI1*0CCEC", "CcecI1*");
1475 if (err)
1476 return err;
1477 err = extron_send_and_wait(extron, NULL, "WO0*CCEC", "CcecO0");
1478 if (err)
1479 return err;
1481 extron->hpd_never_low = hpd_never_low;
1483 /* Pull input port HPD low if all output ports also have a low HPD */
1484 if (hpd_never_low) {
1485 dev_info(extron->dev, "Always keep input HPD high\n");
1486 } else {
1487 dev_info(extron->dev, "Pull input HPD low if all output HPDs are low\n");
1488 extron_send_and_wait(extron, NULL, "W1ihpd", "Ihpd1");
1491 for (p = 0; p < extron->num_ports; p++) {
1492 u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL;
1494 if (vendor_id)
1495 caps &= ~CEC_CAP_LOG_ADDRS;
1496 port = kzalloc(sizeof(*port), GFP_KERNEL);
1497 if (!port)
1498 return -ENOMEM;
1500 INIT_WORK(&port->irq_work, extron_irq_work_handler);
1501 spin_lock_init(&port->msg_lock);
1502 mutex_init(&port->video_lock);
1503 port->extron = extron;
1504 port->is_input = p >= extron->num_out_ports;
1505 port->direction = port->is_input ? 'I' : 'O';
1506 port->port.port = 1 + (port->is_input ? p - extron->num_out_ports : p);
1507 port->port.splitter = &extron->splitter;
1508 port->phys_addr = CEC_PHYS_ADDR_INVALID;
1509 snprintf(port->name, sizeof(port->name), "%s-%s-%u",
1510 dev_name(&serio->dev), port->is_input ? "in" : "out",
1511 port->port.port);
1513 port->dev = extron->dev;
1514 port->adap = cec_allocate_adapter(&extron_cec_adap_ops, port,
1515 port->name, caps, 1);
1516 err = PTR_ERR_OR_ZERO(port->adap);
1517 if (err < 0) {
1518 kfree(port);
1519 return err;
1522 port->adap->xfer_timeout_ms = EXTRON_TIMEOUT_SECS * 1000;
1523 port->port.adap = port->adap;
1524 port->vdev = extron_videodev;
1525 port->vdev.lock = &port->video_lock;
1526 port->vdev.v4l2_dev = &extron->v4l2_dev;
1527 port->vdev.ctrl_handler = &port->hdl;
1528 port->vdev.device_caps = V4L2_CAP_EDID;
1529 video_set_drvdata(&port->vdev, port);
1531 v4l2_ctrl_handler_init(&port->hdl, 2);
1533 if (port->is_input) {
1534 port->vdev.vfl_dir = VFL_DIR_RX;
1535 port->ctrl_rx_power_present =
1536 v4l2_ctrl_new_std(&port->hdl, NULL,
1537 V4L2_CID_DV_RX_POWER_PRESENT,
1538 0, 1, 0, 0);
1539 port->has_edid = true;
1540 } else {
1541 port->vdev.vfl_dir = VFL_DIR_TX;
1542 port->ctrl_tx_hotplug =
1543 v4l2_ctrl_new_std(&port->hdl, NULL,
1544 V4L2_CID_DV_TX_HOTPLUG,
1545 0, 1, 0, 0);
1546 port->ctrl_tx_edid_present =
1547 v4l2_ctrl_new_std(&port->hdl, NULL,
1548 V4L2_CID_DV_TX_EDID_PRESENT,
1549 0, 1, 0, 0);
1552 err = port->hdl.error;
1553 if (err < 0) {
1554 cec_delete_adapter(port->adap);
1555 kfree(port);
1556 return err;
1558 extron->ports[p] = port;
1559 extron->splitter_ports[p] = &port->port;
1560 if (port->is_input && manufacturer_name[0])
1561 extron_write_edid(port, hdmi_edid, 2);
1564 /* Enable CEC (manual mode, i.e. controlled by the driver) */
1565 err = extron_send_and_wait(extron, NULL, "WI1*20CCEC", "CcecI1*");
1566 if (err)
1567 return err;
1569 err = extron_send_and_wait(extron, NULL, "WO20*CCEC", "CcecO20");
1570 if (err)
1571 return err;
1573 /* Set logical addresses to 15 */
1574 err = extron_send_and_wait(extron, NULL, "WI1*15LCEC", "LcecI1*15");
1575 if (err)
1576 return err;
1578 for (p = 0; p < extron->num_out_ports; p++) {
1579 char cmd[20];
1580 char resp[20];
1582 snprintf(cmd, sizeof(cmd), "WO%u*15LCEC", p + 1);
1583 snprintf(resp, sizeof(resp), "LcecO%u*15", p + 1);
1584 err = extron_send_and_wait(extron, extron->ports[p], cmd, resp);
1585 if (err)
1586 return err;
1590 * The Extron is now ready for operation. Specifically it is now
1591 * possible to retrieve EDIDs.
1593 extron->is_ready = true;
1595 /* Query HDCP and Signal states, used to update the initial state */
1596 err = extron_send_and_wait(extron, NULL, "WHDCP", "Hdcp");
1597 if (err)
1598 return err;
1600 return extron_send_and_wait(extron, NULL, "WLS", "Sig");
1603 static int extron_setup_thread(void *_extron)
1605 struct extron *extron = _extron;
1606 struct extron_port *port;
1607 unsigned int p;
1608 bool poll_splitter = false;
1609 bool was_connected = true;
1610 int err;
1612 while (1) {
1613 if (kthread_should_stop())
1614 return 0;
1615 err = extron_send_and_wait(extron, NULL, "W3CV", "Vrb3");
1616 // that should make it possible to detect a serio disconnect
1617 // here by stopping the workqueue
1618 if (err >= 0)
1619 break;
1620 was_connected = false;
1621 ssleep(1);
1625 * If the Extron was not connected at probe() time, i.e. it just got
1626 * powered up and while the serial port is working, the firmware is
1627 * still booting up, then wait 10 seconds for the firmware to settle.
1629 * Trying to continue too soon means that some commands will not
1630 * work yet.
1632 if (!was_connected)
1633 ssleep(10);
1635 err = extron_setup(extron);
1636 if (err)
1637 goto disable_ports;
1639 for (p = 0; p < extron->num_ports; p++) {
1640 struct cec_log_addrs log_addrs = {};
1642 port = extron->ports[p];
1643 if (port->is_input && manufacturer_name[0])
1644 v4l2_disable_ioctl(&port->vdev, VIDIOC_S_EDID);
1645 err = video_register_device(&port->vdev, VFL_TYPE_VIDEO, -1);
1646 if (err) {
1647 v4l2_err(&extron->v4l2_dev, "Failed to register video device\n");
1648 goto disable_ports;
1651 err = cec_register_adapter(port->adap, extron->dev);
1652 if (err < 0)
1653 goto disable_ports;
1654 port->dev = &port->adap->devnode.dev;
1655 port->cec_was_registered = true;
1657 * This driver is unusual in that the whole setup takes place
1658 * in a thread since it can take such a long time before the
1659 * Extron Splitter boots up, and you do not want to block the
1660 * probe function on this driver. In addition, as soon as
1661 * CEC adapters come online, they can be used, and you cannot
1662 * just unregister them again if an error occurs, since that
1663 * can delete the underlying CEC adapter, which might already
1664 * be in use.
1666 * So we take an additional reference to the adapter. This
1667 * allows us to unregister the device node if needed, without
1668 * deleting the actual adapter.
1670 * In the disconnect function we will do the corresponding
1671 * put call to ensure the adapter is deleted.
1673 cec_get_device(port->adap);
1676 * If vendor_id wasn't set, then userspace configures the
1677 * CEC devices. Otherwise the driver configures the CEC
1678 * devices as TV (input) and Playback (outputs) devices
1679 * and the driver processes all CEC messages.
1681 if (!vendor_id)
1682 continue;
1684 log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
1685 log_addrs.num_log_addrs = 1;
1686 log_addrs.vendor_id = vendor_id;
1687 if (port->is_input) {
1688 strscpy(log_addrs.osd_name, "Splitter In",
1689 sizeof(log_addrs.osd_name));
1690 log_addrs.log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV;
1691 log_addrs.primary_device_type[0] = CEC_OP_PRIM_DEVTYPE_TV;
1692 log_addrs.all_device_types[0] = CEC_OP_ALL_DEVTYPE_TV;
1693 } else {
1694 snprintf(log_addrs.osd_name, sizeof(log_addrs.osd_name),
1695 "Splitter Out%u", port->port.port);
1696 log_addrs.log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK;
1697 log_addrs.primary_device_type[0] = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
1698 log_addrs.all_device_types[0] = CEC_OP_ALL_DEVTYPE_PLAYBACK;
1700 err = cec_s_log_addrs(port->adap, &log_addrs, false);
1701 if (err < 0)
1702 goto disable_ports;
1704 poll_splitter = true;
1706 port = extron->ports[extron->num_out_ports];
1707 while (!kthread_should_stop()) {
1708 ssleep(1);
1709 if (hpd_never_low != extron->hpd_never_low) {
1711 * Keep input port HPD high at all times, or pull it low
1712 * if all output ports also have a low HPD
1714 if (hpd_never_low) {
1715 dev_info(extron->dev, "Always keep input HPD high\n");
1716 extron_send_and_wait(extron, NULL, "W0ihpd", "Ihpd0");
1717 } else {
1718 dev_info(extron->dev, "Pull input HPD low if all output HPDs are low\n");
1719 extron_send_and_wait(extron, NULL, "W1ihpd", "Ihpd1");
1721 extron->hpd_never_low = hpd_never_low;
1723 if (poll_splitter &&
1724 cec_splitter_poll(&extron->splitter, port->adap, debug) &&
1725 manufacturer_name[0]) {
1727 * Sinks were lost, so see if the input edid needs to
1728 * be updated.
1730 cancel_delayed_work_sync(&extron->work_update_edid);
1731 schedule_delayed_work(&extron->work_update_edid,
1732 msecs_to_jiffies(1000));
1735 return 0;
1737 disable_ports:
1738 extron->is_ready = false;
1739 for (p = 0; p < extron->num_ports; p++) {
1740 struct extron_port *port = extron->ports[p];
1742 if (!port)
1743 continue;
1744 port->disconnected = true;
1745 cancel_work_sync(&port->irq_work);
1746 video_unregister_device(&port->vdev);
1747 if (port->cec_was_registered)
1748 cec_unregister_adapter(port->adap);
1750 cancel_delayed_work_sync(&extron->work_update_edid);
1751 complete(&extron->edid_completion);
1752 dev_err(extron->dev, "Setup failed with error %d\n", err);
1753 while (!kthread_should_stop())
1754 ssleep(1);
1755 return err;
1758 static int extron_connect(struct serio *serio, struct serio_driver *drv)
1760 struct extron *extron;
1761 int err = -ENOMEM;
1763 if (manufacturer_name[0] &&
1764 (!isupper(manufacturer_name[0]) ||
1765 !isupper(manufacturer_name[1]) ||
1766 !isupper(manufacturer_name[2]))) {
1767 dev_warn(&serio->dev, "ignoring invalid manufacturer name\n");
1768 manufacturer_name[0] = 0;
1771 extron = kzalloc(sizeof(*extron), GFP_KERNEL);
1773 if (!extron)
1774 return -ENOMEM;
1776 extron->serio = serio;
1777 extron->dev = &serio->dev;
1778 mutex_init(&extron->serio_lock);
1779 mutex_init(&extron->edid_lock);
1780 INIT_DELAYED_WORK(&extron->work_update_edid, update_edid_work);
1782 err = v4l2_device_register(extron->dev, &extron->v4l2_dev);
1783 if (err)
1784 goto free_device;
1786 err = serio_open(serio, drv);
1787 if (err)
1788 goto unreg_v4l2_dev;
1790 serio_set_drvdata(serio, extron);
1791 init_completion(&extron->edid_completion);
1793 extron->kthread_setup = kthread_run(extron_setup_thread, extron,
1794 "extron-da-hd-4k-plus-cec-%s", dev_name(&serio->dev));
1795 if (!IS_ERR(extron->kthread_setup))
1796 return 0;
1798 dev_err(extron->dev, "kthread_run() failed\n");
1799 err = PTR_ERR(extron->kthread_setup);
1801 extron->serio = NULL;
1802 serio_set_drvdata(serio, NULL);
1803 serio_close(serio);
1804 unreg_v4l2_dev:
1805 v4l2_device_unregister(&extron->v4l2_dev);
1806 free_device:
1807 mutex_destroy(&extron->edid_lock);
1808 mutex_destroy(&extron->serio_lock);
1809 kfree(extron);
1810 return err;
1813 static const struct serio_device_id extron_serio_ids[] = {
1815 .type = SERIO_RS232,
1816 .proto = SERIO_EXTRON_DA_HD_4K_PLUS,
1817 .id = SERIO_ANY,
1818 .extra = SERIO_ANY,
1820 { 0 }
1823 MODULE_DEVICE_TABLE(serio, extron_serio_ids);
1825 static struct serio_driver extron_drv = {
1826 .driver = {
1827 .name = "extron-da-hd-4k-plus-cec",
1829 .description = "Extron DA HD 4K PLUS HDMI CEC driver",
1830 .id_table = extron_serio_ids,
1831 .interrupt = extron_interrupt,
1832 .connect = extron_connect,
1833 .disconnect = extron_disconnect,
1836 module_serio_driver(extron_drv);