1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2021-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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");
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
)
167 for (i
= 0; i
< 100; i
++) {
168 err
= serio_write(serio
, byte
);
171 usleep_range(80, 120);
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
)
183 for (; !err
&& *command
; command
++)
184 err
= extron_send_byte(serio
, *command
);
186 err
= extron_send_byte(serio
, '\r');
188 for (; !err
&& len
; len
--)
189 err
= extron_send_byte(serio
, *bin
++);
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
;
202 dev_info(extron
->dev
, "transmit %s (response: %s)\n",
205 dev_info(extron
->dev
, "transmit %s\n", cmd
);
208 mutex_lock(&extron
->serio_lock
);
210 init_completion(&port
->cmd_done
);
212 port
->response
= response
;
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
);
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
);
233 extron
->cmd_error
= 0;
237 port
->response
= NULL
;
239 extron
->response
= NULL
;
240 mutex_unlock(&extron
->serio_lock
);
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
;
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;
271 if (!dtd
[0] && !dtd
[1])
273 w
= dtd
[2] + ((dtd
[4] & 0xf0) << 4);
274 h
= dtd
[5] + ((dtd
[7] & 0xf0) << 4);
275 if (w
!= 3840 || h
!= 2160)
278 w
+= dtd
[3] + ((dtd
[4] & 0x0f) << 8);
279 h
+= dtd
[6] + ((dtd
[7] & 0x0f) << 8);
280 pclk
= dtd
[0] + (dtd
[1] << 8);
282 mhz
= div_u64(pclk
, w
* h
);
284 port
->has_4kp30
= true;
286 port
->has_4kp60
= true;
289 if (port
->edid_blocks
== 1)
294 /* Return if not a CTA-861 extension block */
295 if (edid
[0] != 0x02 || edid
[1] != 0x03)
298 /* search Video Data Block (tag 2) */
300 /* Check if there are Data Blocks */
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)
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;
325 case 7: /* Use Extended Tag */
326 switch (edid
[i
+ 1]) {
327 case 0: /* Video Capability Data Block */
328 if (edid
[i
+ 2] & 0x80)
330 if (edid
[i
+ 2] & 0x40)
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;
349 /* Return if not a CTA-861 extension block */
350 if (size
< 256 || edid
[0] != 0x02 || edid
[1] != 0x03)
354 d
= edid
[0x02] & 0x7f;
362 unsigned char tag
= edid
[i
] >> 5;
363 unsigned char len
= edid
[i
] & 0x1f;
365 if (tag
!= want_tag
|| i
+ len
> end
) {
370 if (tag
< 7 || (len
>= 1 && edid
[i
+ 1] == ext_tag
))
377 static void extron_edid_crc(u8
*edid
)
383 for (offset
= 0; offset
< 127; 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;
398 memset(start
, ' ', max_len
);
401 memcpy(start
, s
, len
);
406 static void extron_update_edid(struct extron_port
*port
, unsigned int blocks
)
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);
433 port
->edid_tmp
[offset
+ 2] &= ~0xc0;
435 port
->edid_tmp
[offset
+ 2] |= 0x80;
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
;
450 if (cec_get_edid_spa_location(edid
, blocks
* 128))
453 if (mutex_lock_interruptible(&extron
->edid_lock
))
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
),
466 ret
= extron_send_and_wait(port
->extron
, port
, "WI1,in.binEDID",
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);
480 mutex_unlock(&extron
->edid_lock
);
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;
499 for (out
= 0; has_4kp60
&& out
< extron
->num_out_ports
; out
++) {
500 p
= extron
->ports
[out
];
502 has_4kp60
= p
->has_4kp60
;
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 */
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
)
530 in
->has_4kp60
= has_4kp60
;
531 in
->has_4kp30
= has_4kp30
;
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];
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
))
554 extron
->edid_bytes_read
= 0;
555 extron
->edid_port
= port
;
556 port
->edid_blocks
= 0;
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;
569 v4l2_ctrl_s_ctrl(port
->ctrl_tx_edid_present
, 1);
572 extron
->edid_reading
= false;
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
;
589 bool update_has_signal
;
591 bool update_has_edid
;
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
)
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
);
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
,
628 if (port
->has_edid
) {
629 port
->port
.found_sink
= true;
630 port
->port
.lost_sink_ts
= ktime_set(0, 0);
632 port
->port
.lost_sink_ts
= ktime_get();
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
);
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
;
656 if (!port
|| port
->disconnected
)
659 if (len
< 5 || (len
- 2) % 3 || data
[len
- 2] != '*')
662 while (*data
!= '*') {
663 int v
= hex2bin(&msg
.msg
[msg
.len
], data
+ 1, 1);
665 if (*data
!= '%' || v
)
671 spin_lock_irqsave(&port
->msg_lock
, irq_flags
);
672 idx
= (port
->rx_msg_cur_idx
+ port
->rx_msg_num
) %
674 if (port
->rx_msg_num
== NUM_MSGS
) {
676 "message queue is full, dropping %*ph\n",
678 spin_unlock_irqrestore(&port
->msg_lock
,
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
);
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
;
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;
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
)
716 extron_port_signal_change(extron
->ports
[extron
->num_out_ports
],
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
;
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;
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
)
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
)
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
;
766 spin_lock_irqsave(&port
->msg_lock
, irq_flags
);
767 if (!port
->update_phys_addr
&& port
->phys_addr
!= pa
) {
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
;
787 tx_status
= CEC_TX_STATUS_NACK
| CEC_TX_STATUS_MAX_RETRIES
;
790 tx_status
= CEC_TX_STATUS_OK
;
793 tx_status
= CEC_TX_STATUS_ERROR
;
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
)
809 while (extron
->edid_bytes_read
< sizeof(port
->edid
) && *hex
) {
810 int err
= hex2bin(&port
->edid
[extron
->edid_bytes_read
], hex
, 1);
813 extron
->edid_reading
= false;
814 complete(&extron
->edid_completion
);
817 extron
->edid_bytes_read
++;
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
))
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
,
838 struct extron
*extron
= serio_get_drvdata(serio
);
839 struct extron_port
*port
= NULL
;
843 if (data
== '\r' || data
== '\n') {
844 if (extron
->idx
== 0)
846 memcpy(extron
->data
, extron
->buf
, extron
->idx
);
847 extron
->len
= extron
->idx
;
848 extron
->data
[extron
->len
] = 0;
850 dev_info(extron
->dev
, "received %s\n", extron
->data
);
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
],
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
],
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';
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 &&
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]) &&
946 extron
->cmd_error
= (extron
->data
[1] - '0') * 10 +
947 extron
->data
[2] - '0';
948 extron
->response
= NULL
;
949 complete(&extron
->cmd_done
);
955 memcpy(extron
->reply
, extron
->data
, extron
->len
);
956 extron
->reply
[extron
->len
] = 0;
958 extron
->response
= NULL
;
959 complete(&extron
->cmd_done
);
961 port
->response
= NULL
;
962 complete(&port
->cmd_done
);
967 if (extron
->idx
>= DATA_SIZE
- 1) {
968 dev_info(extron
->dev
,
969 "throwing away %d bytes of garbage\n", extron
->idx
);
972 extron
->buf
[extron
->idx
++] = (char)data
;
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
);
988 u8 la
= log_addr
== CEC_LOG_ADDR_INVALID
? 15 : log_addr
;
991 if (port
->disconnected
)
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];
1009 if (port
->disconnected
)
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
)
1027 dev_info(port
->extron
->dev
, "unconfigured port %d (%s)\n",
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
)
1041 dev_info(port
->extron
->dev
, "configured port %d (%s)\n",
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
;
1056 if (port
->disconnected
|| port
->is_input
)
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
);
1068 if (port
->disconnected
)
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...) \
1079 seq_printf((file), fmt, ## arg); \
1081 pr_info("cec-%s: " fmt, (adap)->name, ## arg); \
1084 static const char * const pwr_state
[] = {
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
);
1101 log_printf(adap
, file
,
1102 "\tport %u: %s signal, %s edid, %s 4kp30, %s 4kp60, %sQS/%sQY, is %s\n",
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
]);
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",
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",
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",
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
;
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");
1157 log_printf(adap
, file
,
1158 "pull input HPD low if all output HPDs are low\n");
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",
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
)
1180 for (i
= 0; i
< port
->edid_blocks
* 128; i
+= 16) {
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
);
1209 static int extron_enum_input(struct file
*file
, void *priv
, struct v4l2_input
*inp
)
1211 struct extron_port
*port
= video_drvdata(file
);
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
;
1222 static int extron_g_input(struct file
*file
, void *priv
, unsigned int *i
)
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
);
1239 out
->type
= V4L2_OUTPUT_TYPE_ANALOG
;
1240 snprintf(out
->name
, sizeof(out
->name
), "HDMI OUT %u", port
->port
.port
);
1244 static int extron_g_output(struct file
*file
, void *priv
, unsigned int *o
)
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
)
1265 if (!port
->has_edid
)
1267 if (!port
->read_edid
)
1268 extron_read_edid(port
);
1269 if (!port
->read_edid
)
1271 if (edid
->start_block
== 0 && edid
->blocks
== 0) {
1272 edid
->blocks
= port
->edid_blocks
;
1275 if (edid
->start_block
>= port
->edid_blocks
)
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);
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
)
1293 /* Unfortunately it is not possible to clear the EDID */
1294 if (edid
->blocks
== 0)
1297 if (edid
->blocks
> MAX_EDID_BLOCKS
) {
1298 edid
->blocks
= MAX_EDID_BLOCKS
;
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
,
1345 .release
= video_device_release_empty
,
1348 static void extron_disconnect(struct serio
*serio
)
1350 struct extron
*extron
= serio_get_drvdata(serio
);
1353 kthread_stop(extron
->kthread_setup
);
1355 for (p
= 0; p
< extron
->num_ports
; p
++) {
1356 struct extron_port
*port
= extron
->ports
[p
];
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
];
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
1379 cec_put_device(port
->adap
);
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
];
1393 v4l2_ctrl_handler_free(&port
->hdl
);
1394 mutex_destroy(&port
->video_lock
);
1397 mutex_destroy(&extron
->edid_lock
);
1398 mutex_destroy(&extron
->serio_lock
);
1399 extron
->serio
= NULL
;
1400 serio_set_drvdata(serio
, NULL
);
1404 static int extron_setup(struct extron
*extron
)
1406 struct serio
*serio
= extron
->serio
;
1407 struct extron_port
*port
;
1408 u8
*reply
= extron
->reply
;
1410 unsigned int major
, minor
;
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");
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");
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 ");
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");
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");
1460 err
= extron_send_and_wait(extron
, NULL
, "2i", "Inf02*");
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*");
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
));
1474 err
= extron_send_and_wait(extron
, NULL
, "WI1*0CCEC", "CcecI1*");
1477 err
= extron_send_and_wait(extron
, NULL
, "WO0*CCEC", "CcecO0");
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");
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
;
1495 caps
&= ~CEC_CAP_LOG_ADDRS
;
1496 port
= kzalloc(sizeof(*port
), GFP_KERNEL
);
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",
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
);
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
,
1539 port
->has_edid
= true;
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
,
1546 port
->ctrl_tx_edid_present
=
1547 v4l2_ctrl_new_std(&port
->hdl
, NULL
,
1548 V4L2_CID_DV_TX_EDID_PRESENT
,
1552 err
= port
->hdl
.error
;
1554 cec_delete_adapter(port
->adap
);
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*");
1569 err
= extron_send_and_wait(extron
, NULL
, "WO20*CCEC", "CcecO20");
1573 /* Set logical addresses to 15 */
1574 err
= extron_send_and_wait(extron
, NULL
, "WI1*15LCEC", "LcecI1*15");
1578 for (p
= 0; p
< extron
->num_out_ports
; p
++) {
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
);
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");
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
;
1608 bool poll_splitter
= false;
1609 bool was_connected
= true;
1613 if (kthread_should_stop())
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
1620 was_connected
= false;
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
1635 err
= extron_setup(extron
);
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);
1647 v4l2_err(&extron
->v4l2_dev
, "Failed to register video device\n");
1651 err
= cec_register_adapter(port
->adap
, extron
->dev
);
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
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.
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
;
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);
1704 poll_splitter
= true;
1706 port
= extron
->ports
[extron
->num_out_ports
];
1707 while (!kthread_should_stop()) {
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");
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
1730 cancel_delayed_work_sync(&extron
->work_update_edid
);
1731 schedule_delayed_work(&extron
->work_update_edid
,
1732 msecs_to_jiffies(1000));
1738 extron
->is_ready
= false;
1739 for (p
= 0; p
< extron
->num_ports
; p
++) {
1740 struct extron_port
*port
= extron
->ports
[p
];
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())
1758 static int extron_connect(struct serio
*serio
, struct serio_driver
*drv
)
1760 struct extron
*extron
;
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
);
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
);
1786 err
= serio_open(serio
, drv
);
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
))
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
);
1805 v4l2_device_unregister(&extron
->v4l2_dev
);
1807 mutex_destroy(&extron
->edid_lock
);
1808 mutex_destroy(&extron
->serio_lock
);
1813 static const struct serio_device_id extron_serio_ids
[] = {
1815 .type
= SERIO_RS232
,
1816 .proto
= SERIO_EXTRON_DA_HD_4K_PLUS
,
1823 MODULE_DEVICE_TABLE(serio
, extron_serio_ids
);
1825 static struct serio_driver extron_drv
= {
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
);