Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: cec: core: add new CEC_MSG_FL_REPLY_VENDOR_ID flag

If this flag is set, then the reply is expected to consist of
the CEC_MSG_VENDOR_COMMAND_WITH_ID opcode followed by the Vendor ID (as
used in bytes 1-4 of the message), followed by the struct cec_msg reply
field.

Note that this assumes that the byte after the Vendor ID is a
vendor-specific opcode.

This flag makes it easier to wait for replies to vendor commands,
using the same CEC framework support for waiting for regular replies.

Support for this flag is indicated by setting the new
CEC_CAP_REPLY_VENDOR_ID capability.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
613f2150 2c25dcc2

+64 -16
+6
Documentation/userspace-api/media/cec/cec-ioc-adap-g-caps.rst
··· 137 137 - 0x00000100 138 138 - If this capability is set, then :ref:`CEC_ADAP_G_CONNECTOR_INFO` can 139 139 be used. 140 + * .. _`CEC-CAP-REPLY-VENDOR-ID`: 141 + 142 + - ``CEC_CAP_REPLY_VENDOR_ID`` 143 + - 0x00000200 144 + - If this capability is set, then 145 + :ref:`CEC_MSG_FL_REPLY_VENDOR_ID <cec-msg-flags>` can be used. 140 146 141 147 Return Value 142 148 ============
+15
Documentation/userspace-api/media/cec/cec-ioc-receive.rst
··· 232 232 capability. If that is not set, then the ``EPERM`` error code is 233 233 returned. 234 234 235 + * .. _`CEC-MSG-FL-REPLY-VENDOR-ID`: 236 + 237 + - ``CEC_MSG_FL_REPLY_VENDOR_ID`` 238 + - 4 239 + - This flag is only available if the ``CEC_CAP_REPLY_VENDOR_ID`` capability 240 + is set. If this flag is set, then the reply is expected to consist of 241 + the ``CEC_MSG_VENDOR_COMMAND_WITH_ID`` opcode followed by the Vendor ID 242 + (in bytes 1-4 of the message), followed by the ``struct cec_msg`` 243 + ``reply`` field. 244 + 245 + Note that this assumes that the byte after the Vendor ID is a 246 + vendor-specific opcode. 247 + 248 + This flag makes it easier to wait for replies to vendor commands. 249 + 235 250 .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{10.8cm}| 236 251 237 252 .. _cec-tx-status:
+37 -15
drivers/media/cec/core/cec-adap.c
··· 673 673 /* Retry this message */ 674 674 data->attempts -= attempts_made; 675 675 if (msg->timeout) 676 - dprintk(2, "retransmit: %*ph (attempts: %d, wait for 0x%02x)\n", 677 - msg->len, msg->msg, data->attempts, msg->reply); 676 + dprintk(2, "retransmit: %*ph (attempts: %d, wait for %*ph)\n", 677 + msg->len, msg->msg, data->attempts, 678 + data->match_len, data->match_reply); 678 679 else 679 680 dprintk(2, "retransmit: %*ph (attempts: %d)\n", 680 681 msg->len, msg->msg, data->attempts); ··· 781 780 { 782 781 struct cec_data *data; 783 782 bool is_raw = msg_is_raw(msg); 783 + bool reply_vendor_id = msg->flags & CEC_MSG_FL_REPLY_VENDOR_ID; 784 784 int err; 785 785 786 786 if (adap->devnode.unregistered) ··· 796 794 msg->tx_low_drive_cnt = 0; 797 795 msg->tx_error_cnt = 0; 798 796 msg->sequence = 0; 797 + msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS | CEC_MSG_FL_RAW | 798 + CEC_MSG_FL_REPLY_VENDOR_ID; 799 799 800 - if (msg->reply && msg->timeout == 0) { 800 + if ((reply_vendor_id || msg->reply) && msg->timeout == 0) { 801 801 /* Make sure the timeout isn't 0. */ 802 802 msg->timeout = 1000; 803 803 } 804 - msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS | CEC_MSG_FL_RAW; 805 804 806 805 if (!msg->timeout) 807 806 msg->flags &= ~CEC_MSG_FL_REPLY_TO_FOLLOWERS; ··· 810 807 /* Sanity checks */ 811 808 if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { 812 809 dprintk(1, "%s: invalid length %d\n", __func__, msg->len); 810 + return -EINVAL; 811 + } 812 + if (reply_vendor_id && 813 + (msg->len < 6 || msg->msg[1] != CEC_MSG_VENDOR_COMMAND_WITH_ID)) { 814 + dprintk(1, "%s: message too short or not <Vendor Command With ID>\n", __func__); 813 815 return -EINVAL; 814 816 } 815 817 ··· 908 900 __func__); 909 901 return -ENONET; 910 902 } 911 - if (msg->reply) { 912 - dprintk(1, "%s: invalid msg->reply\n", __func__); 903 + if (reply_vendor_id || msg->reply) { 904 + dprintk(1, "%s: adapter is unconfigured so reply is not supported\n", 905 + __func__); 913 906 return -EINVAL; 914 907 } 915 908 } ··· 932 923 data->fh = fh; 933 924 data->adap = adap; 934 925 data->blocking = block; 926 + if (reply_vendor_id) { 927 + memcpy(data->match_reply, msg->msg + 1, 4); 928 + data->match_reply[4] = msg->reply; 929 + data->match_len = 5; 930 + } else if (msg->timeout) { 931 + data->match_reply[0] = msg->reply; 932 + data->match_len = 1; 933 + } 935 934 936 935 init_completion(&data->c); 937 936 INIT_DELAYED_WORK(&data->work, cec_wait_timeout); ··· 1228 1211 if (!abort && dst->msg[1] == CEC_MSG_INITIATE_ARC && 1229 1212 (cmd == CEC_MSG_REPORT_ARC_INITIATED || 1230 1213 cmd == CEC_MSG_REPORT_ARC_TERMINATED) && 1231 - (dst->reply == CEC_MSG_REPORT_ARC_INITIATED || 1232 - dst->reply == CEC_MSG_REPORT_ARC_TERMINATED)) 1214 + (data->match_reply[0] == CEC_MSG_REPORT_ARC_INITIATED || 1215 + data->match_reply[0] == CEC_MSG_REPORT_ARC_TERMINATED)) { 1233 1216 dst->reply = cmd; 1217 + data->match_reply[0] = cmd; 1218 + } 1234 1219 1235 1220 /* Does the command match? */ 1236 1221 if ((abort && cmd != dst->msg[1]) || 1237 - (!abort && cmd != dst->reply)) 1222 + (!abort && memcmp(data->match_reply, msg->msg + 1, data->match_len))) 1238 1223 continue; 1239 1224 1240 1225 /* Does the addressing match? */ ··· 2337 2318 } 2338 2319 data = adap->transmitting; 2339 2320 if (data) 2340 - seq_printf(file, "transmitting message: %*ph (reply: %02x, timeout: %ums)\n", 2341 - data->msg.len, data->msg.msg, data->msg.reply, 2321 + seq_printf(file, "transmitting message: %*ph (reply: %*ph, timeout: %ums)\n", 2322 + data->msg.len, data->msg.msg, 2323 + data->match_len, data->match_reply, 2342 2324 data->msg.timeout); 2343 2325 seq_printf(file, "pending transmits: %u\n", adap->transmit_queue_sz); 2344 2326 list_for_each_entry(data, &adap->transmit_queue, list) { 2345 - seq_printf(file, "queued tx message: %*ph (reply: %02x, timeout: %ums)\n", 2346 - data->msg.len, data->msg.msg, data->msg.reply, 2327 + seq_printf(file, "queued tx message: %*ph (reply: %*ph, timeout: %ums)\n", 2328 + data->msg.len, data->msg.msg, 2329 + data->match_len, data->match_reply, 2347 2330 data->msg.timeout); 2348 2331 } 2349 2332 list_for_each_entry(data, &adap->wait_queue, list) { 2350 - seq_printf(file, "message waiting for reply: %*ph (reply: %02x, timeout: %ums)\n", 2351 - data->msg.len, data->msg.msg, data->msg.reply, 2333 + seq_printf(file, "message waiting for reply: %*ph (reply: %*ph, timeout: %ums)\n", 2334 + data->msg.len, data->msg.msg, 2335 + data->match_len, data->match_reply, 2352 2336 data->msg.timeout); 2353 2337 } 2354 2338
+1 -1
drivers/media/cec/core/cec-core.c
··· 273 273 adap->cec_pin_is_high = true; 274 274 adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; 275 275 adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; 276 - adap->capabilities = caps; 276 + adap->capabilities = caps | CEC_CAP_REPLY_VENDOR_ID; 277 277 if (debug_phys_addr) 278 278 adap->capabilities |= CEC_CAP_PHYS_ADDR; 279 279 adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
+2
include/media/cec.h
··· 66 66 struct list_head xfer_list; 67 67 struct cec_adapter *adap; 68 68 struct cec_msg msg; 69 + u8 match_len; 70 + u8 match_reply[5]; 69 71 struct cec_fh *fh; 70 72 struct delayed_work work; 71 73 struct completion c;
+3
include/uapi/linux/cec.h
··· 165 165 /* cec_msg flags field */ 166 166 #define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0) 167 167 #define CEC_MSG_FL_RAW (1 << 1) 168 + #define CEC_MSG_FL_REPLY_VENDOR_ID (1 << 2) 168 169 169 170 /* cec_msg tx/rx_status field */ 170 171 #define CEC_TX_STATUS_OK (1 << 0) ··· 340 339 #define CEC_CAP_MONITOR_PIN (1 << 7) 341 340 /* CEC_ADAP_G_CONNECTOR_INFO is available */ 342 341 #define CEC_CAP_CONNECTOR_INFO (1 << 8) 342 + /* CEC_MSG_FL_REPLY_VENDOR_ID is available */ 343 + #define CEC_CAP_REPLY_VENDOR_ID (1 << 9) 343 344 344 345 /** 345 346 * struct cec_caps - CEC capabilities structure.