| 1 |
|
| 2 | |
| 3 | * cec - HDMI Consumer Electronics Control support header
|
| 4 | *
|
| 5 | * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
| 6 |
|
| 7 |
|
| 8 | #ifndef _MEDIA_CEC_H
|
| 9 | #define _MEDIA_CEC_H
|
| 10 |
|
| 11 | #include <linux/poll.h>
|
| 12 | #include <linux/fs.h>
|
| 13 | #include <linux/device.h>
|
| 14 | #include <linux/cdev.h>
|
| 15 | #include <linux/kthread.h>
|
| 16 | #include <linux/timer.h>
|
| 17 | #include <linux/cec-funcs.h>
|
| 18 | #include <media/rc-core.h>
|
| 19 |
|
| 20 | #define CEC_CAP_DEFAULTS (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | \
|
| 21 | CEC_CAP_PASSTHROUGH | CEC_CAP_RC)
|
| 22 |
|
| 23 | |
| 24 | * struct cec_devnode - cec device node
|
| 25 | * @dev: cec device
|
| 26 | * @cdev: cec character device
|
| 27 | * @minor: device node minor number
|
| 28 | * @lock: lock to serialize open/release and registration
|
| 29 | * @registered: the device was correctly registered
|
| 30 | * @unregistered: the device was unregistered
|
| 31 | * @lock_fhs: lock to control access to @fhs
|
| 32 | * @fhs: the list of open filehandles (cec_fh)
|
| 33 | *
|
| 34 | * This structure represents a cec-related device node.
|
| 35 | *
|
| 36 | * To add or remove filehandles from @fhs the @lock must be taken first,
|
| 37 | * followed by @lock_fhs. It is safe to access @fhs if either lock is held.
|
| 38 | *
|
| 39 | * The @parent is a physical device. It must be set by core or device drivers
|
| 40 | * before registering the node.
|
| 41 |
|
| 42 | struct cec_devnode {
|
| 43 |
|
| 44 | struct device dev;
|
| 45 | struct cdev cdev;
|
| 46 |
|
| 47 |
|
| 48 | int minor;
|
| 49 |
|
| 50 | struct mutex lock;
|
| 51 | bool registered;
|
| 52 | bool unregistered;
|
| 53 |
|
| 54 | struct mutex lock_fhs;
|
| 55 | struct list_head fhs;
|
| 56 | };
|
| 57 |
|
| 58 | struct cec_adapter;
|
| 59 | struct cec_data;
|
| 60 | struct cec_pin;
|
| 61 | struct cec_notifier;
|
| 62 |
|
| 63 | struct cec_data {
|
| 64 | struct list_head list;
|
| 65 | struct list_head xfer_list;
|
| 66 | struct cec_adapter *adap;
|
| 67 | struct cec_msg msg;
|
| 68 | u8 match_len;
|
| 69 | u8 match_reply[5];
|
| 70 | struct cec_fh *fh;
|
| 71 | struct delayed_work work;
|
| 72 | struct completion c;
|
| 73 | u8 attempts;
|
| 74 | bool blocking;
|
| 75 | bool completed;
|
| 76 | };
|
| 77 |
|
| 78 | struct cec_msg_entry {
|
| 79 | struct list_head list;
|
| 80 | struct cec_msg msg;
|
| 81 | };
|
| 82 |
|
| 83 | struct cec_event_entry {
|
| 84 | struct list_head list;
|
| 85 | struct cec_event ev;
|
| 86 | };
|
| 87 |
|
| 88 | #define CEC_NUM_EVENTS CEC_EVENT_PIN_5V_HIGH
|
| 89 |
|
| 90 | struct cec_fh {
|
| 91 | struct list_head list;
|
| 92 | struct list_head xfer_list;
|
| 93 | struct cec_adapter *adap;
|
| 94 | u8 mode_initiator;
|
| 95 | u8 mode_follower;
|
| 96 |
|
| 97 |
|
| 98 | wait_queue_head_t wait;
|
| 99 | struct mutex lock;
|
| 100 | struct list_head events[CEC_NUM_EVENTS];
|
| 101 | u16 queued_events[CEC_NUM_EVENTS];
|
| 102 | unsigned int total_queued_events;
|
| 103 | struct list_head msgs;
|
| 104 | unsigned int queued_msgs;
|
| 105 | };
|
| 106 |
|
| 107 | #define CEC_SIGNAL_FREE_TIME_RETRY 3
|
| 108 | #define CEC_SIGNAL_FREE_TIME_NEW_INITIATOR 5
|
| 109 | #define CEC_SIGNAL_FREE_TIME_NEXT_XFER 7
|
| 110 |
|
| 111 |
|
| 112 | #define CEC_FREE_TIME_TO_USEC(ft) ((ft) * 2400)
|
| 113 |
|
| 114 | struct cec_adap_ops {
|
| 115 |
|
| 116 | int (*adap_enable)(struct cec_adapter *adap, bool enable);
|
| 117 | int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
|
| 118 | int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable);
|
| 119 | int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
|
| 120 | void (*adap_unconfigured)(struct cec_adapter *adap);
|
| 121 | int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
|
| 122 | u32 signal_free_time, struct cec_msg *msg);
|
| 123 | void (*adap_nb_transmit_canceled)(struct cec_adapter *adap,
|
| 124 | const struct cec_msg *msg);
|
| 125 | void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
|
| 126 | void (*adap_free)(struct cec_adapter *adap);
|
| 127 |
|
| 128 |
|
| 129 | int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf);
|
| 130 | bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line);
|
| 131 |
|
| 132 |
|
| 133 | void (*configured)(struct cec_adapter *adap);
|
| 134 | int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
|
| 135 | };
|
| 136 |
|
| 137 | |
| 138 | * The minimum message length you can receive (excepting poll messages) is 2.
|
| 139 | * With a transfer rate of at most 36 bytes per second this makes 18 messages
|
| 140 | * per second worst case.
|
| 141 | *
|
| 142 | * We queue at most 3 seconds worth of received messages. The CEC specification
|
| 143 | * requires that messages are replied to within a second, so 3 seconds should
|
| 144 | * give more than enough margin. Since most messages are actually more than 2
|
| 145 | * bytes, this is in practice a lot more than 3 seconds.
|
| 146 |
|
| 147 | #define CEC_MAX_MSG_RX_QUEUE_SZ (18 * 3)
|
| 148 |
|
| 149 | |
| 150 | * The transmit queue is limited to 1 second worth of messages (worst case).
|
| 151 | * Messages can be transmitted by userspace and kernel space. But for both it
|
| 152 | * makes no sense to have a lot of messages queued up. One second seems
|
| 153 | * reasonable.
|
| 154 |
|
| 155 | #define CEC_MAX_MSG_TX_QUEUE_SZ (18 * 1)
|
| 156 |
|
| 157 | |
| 158 | * struct cec_adapter - cec adapter structure
|
| 159 | * @owner: module owner
|
| 160 | * @name: name of the CEC adapter
|
| 161 | * @devnode: device node for the /dev/cecX device
|
| 162 | * @lock: mutex controlling access to this structure
|
| 163 | * @rc: remote control device
|
| 164 | * @transmit_queue: queue of pending transmits
|
| 165 | * @transmit_queue_sz: number of pending transmits
|
| 166 | * @wait_queue: queue of transmits waiting for a reply
|
| 167 | * @transmitting: CEC messages currently being transmitted
|
| 168 | * @transmit_in_progress: true if a transmit is in progress
|
| 169 | * @transmit_in_progress_aborted: true if a transmit is in progress is to be
|
| 170 | * aborted. This happens if the logical address is
|
| 171 | * invalidated while the transmit is ongoing. In that
|
| 172 | * case the transmit will finish, but will not retransmit
|
| 173 | * and be marked as ABORTED.
|
| 174 | * @xfer_timeout_ms: the transfer timeout in ms.
|
| 175 | * If 0, then timeout after 2100 ms.
|
| 176 | * @kthread_config: kthread used to configure a CEC adapter
|
| 177 | * @config_completion: used to signal completion of the config kthread
|
| 178 | * @kthread: main CEC processing thread
|
| 179 | * @kthread_waitq: main CEC processing wait_queue
|
| 180 | * @ops: cec adapter ops
|
| 181 | * @priv: cec driver's private data
|
| 182 | * @capabilities: cec adapter capabilities
|
| 183 | * @available_log_addrs: maximum number of available logical addresses
|
| 184 | * @phys_addr: the current physical address
|
| 185 | * @needs_hpd: if true, then the HDMI HotPlug Detect pin must be high
|
| 186 | * in order to transmit or receive CEC messages. This is usually a HW
|
| 187 | * limitation.
|
| 188 | * @is_enabled: the CEC adapter is enabled
|
| 189 | * @is_claiming_log_addrs: true if cec_claim_log_addrs() is running
|
| 190 | * @is_configuring: the CEC adapter is configuring (i.e. claiming LAs)
|
| 191 | * @must_reconfigure: while configuring, the PA changed, so reclaim LAs
|
| 192 | * @is_configured: the CEC adapter is configured (i.e. has claimed LAs)
|
| 193 | * @cec_pin_is_high: if true then the CEC pin is high. Only used with the
|
| 194 | * CEC pin framework.
|
| 195 | * @adap_controls_phys_addr: if true, then the CEC adapter controls the
|
| 196 | * physical address, i.e. the CEC hardware can detect HPD changes and
|
| 197 | * read the EDID and is not dependent on an external HDMI driver.
|
| 198 | * Drivers that need this can set this field to true after the
|
| 199 | * cec_allocate_adapter() call.
|
| 200 | * @last_initiator: the initiator of the last transmitted message.
|
| 201 | * @monitor_all_cnt: number of filehandles monitoring all msgs
|
| 202 | * @monitor_pin_cnt: number of filehandles monitoring pin changes
|
| 203 | * @follower_cnt: number of filehandles in follower mode
|
| 204 | * @cec_follower: filehandle of the exclusive follower
|
| 205 | * @cec_initiator: filehandle of the exclusive initiator
|
| 206 | * @passthrough: if true, then the exclusive follower is in
|
| 207 | * passthrough mode.
|
| 208 | * @log_addrs: current logical addresses
|
| 209 | * @conn_info: current connector info
|
| 210 | * @tx_timeout_cnt: count the number of Timed Out transmits.
|
| 211 | * Reset to 0 when this is reported in cec_adap_status().
|
| 212 | * @tx_low_drive_cnt: count the number of Low Drive transmits.
|
| 213 | * Reset to 0 when this is reported in cec_adap_status().
|
| 214 | * @tx_error_cnt: count the number of Error transmits.
|
| 215 | * Reset to 0 when this is reported in cec_adap_status().
|
| 216 | * @tx_arb_lost_cnt: count the number of Arb Lost transmits.
|
| 217 | * Reset to 0 when this is reported in cec_adap_status().
|
| 218 | * @tx_low_drive_log_cnt: number of logged Low Drive transmits since the
|
| 219 | * adapter was enabled. Used to avoid flooding the kernel
|
| 220 | * log if this happens a lot.
|
| 221 | * @tx_error_log_cnt: number of logged Error transmits since the adapter was
|
| 222 | * enabled. Used to avoid flooding the kernel log if this
|
| 223 | * happens a lot.
|
| 224 | * @error_inj_tx_timeouts: error injection: the next @error_inj_tx_timeouts
|
| 225 | * transmits will time out.
|
| 226 | * @notifier: CEC notifier
|
| 227 | * @pin: CEC pin status struct
|
| 228 | * @cec_dir: debugfs cec directory
|
| 229 | * @sequence: transmit sequence counter
|
| 230 | * @input_phys: remote control input_phys name
|
| 231 | *
|
| 232 | * This structure represents a cec adapter.
|
| 233 |
|
| 234 | struct cec_adapter {
|
| 235 | struct module *owner;
|
| 236 | char name[32];
|
| 237 | struct cec_devnode devnode;
|
| 238 | struct mutex lock;
|
| 239 | struct rc_dev *rc;
|
| 240 |
|
| 241 | struct list_head transmit_queue;
|
| 242 | unsigned int transmit_queue_sz;
|
| 243 | struct list_head wait_queue;
|
| 244 | struct cec_data *transmitting;
|
| 245 | bool transmit_in_progress;
|
| 246 | bool transmit_in_progress_aborted;
|
| 247 | unsigned int xfer_timeout_ms;
|
| 248 |
|
| 249 | struct task_struct *kthread_config;
|
| 250 | struct completion config_completion;
|
| 251 |
|
| 252 | struct task_struct *kthread;
|
| 253 | wait_queue_head_t kthread_waitq;
|
| 254 |
|
| 255 | const struct cec_adap_ops *ops;
|
| 256 | void *priv;
|
| 257 | u32 capabilities;
|
| 258 | u8 available_log_addrs;
|
| 259 |
|
| 260 | u16 phys_addr;
|
| 261 | bool needs_hpd;
|
| 262 | bool is_enabled;
|
| 263 | bool is_claiming_log_addrs;
|
| 264 | bool is_configuring;
|
| 265 | bool must_reconfigure;
|
| 266 | bool is_configured;
|
| 267 | bool cec_pin_is_high;
|
| 268 | bool adap_controls_phys_addr;
|
| 269 | u8 last_initiator;
|
| 270 | u32 monitor_all_cnt;
|
| 271 | u32 monitor_pin_cnt;
|
| 272 | u32 follower_cnt;
|
| 273 | struct cec_fh *cec_follower;
|
| 274 | struct cec_fh *cec_initiator;
|
| 275 | bool passthrough;
|
| 276 | struct cec_log_addrs log_addrs;
|
| 277 | struct cec_connector_info conn_info;
|
| 278 |
|
| 279 | u32 tx_timeout_cnt;
|
| 280 | u32 tx_low_drive_cnt;
|
| 281 | u32 tx_error_cnt;
|
| 282 | u32 tx_arb_lost_cnt;
|
| 283 | u32 tx_low_drive_log_cnt;
|
| 284 | u32 tx_error_log_cnt;
|
| 285 |
|
| 286 | u32 error_inj_tx_timeouts;
|
| 287 |
|
| 288 | #ifdef CONFIG_CEC_NOTIFIER
|
| 289 | struct cec_notifier *notifier;
|
| 290 | #endif
|
| 291 | #ifdef CONFIG_CEC_PIN
|
| 292 | struct cec_pin *pin;
|
| 293 | #endif
|
| 294 |
|
| 295 | struct dentry *cec_dir;
|
| 296 |
|
| 297 | u32 sequence;
|
| 298 |
|
| 299 | char input_phys[40];
|
| 300 | };
|
| 301 |
|
| 302 | static inline int cec_get_device(struct cec_adapter *adap)
|
| 303 | {
|
| 304 | struct cec_devnode *devnode = &adap->devnode;
|
| 305 |
|
| 306 | |
| 307 | * Check if the cec device is available. This needs to be done with
|
| 308 | * the devnode->lock held to prevent an open/unregister race:
|
| 309 | * without the lock, the device could be unregistered and freed between
|
| 310 | * the devnode->registered check and get_device() calls, leading to
|
| 311 | * a crash.
|
| 312 |
|
| 313 | mutex_lock(&devnode->lock);
|
| 314 | |
| 315 | * return ENODEV if the cec device has been removed
|
| 316 | * already or if it is not registered anymore.
|
| 317 |
|
| 318 | if (!devnode->registered) {
|
| 319 | mutex_unlock(&devnode->lock);
|
| 320 | return -ENODEV;
|
| 321 | }
|
| 322 |
|
| 323 | get_device(&devnode->dev);
|
| 324 | mutex_unlock(&devnode->lock);
|
| 325 | return 0;
|
| 326 | }
|
| 327 |
|
| 328 | static inline void cec_put_device(struct cec_adapter *adap)
|
| 329 | {
|
| 330 | put_device(&adap->devnode.dev);
|
| 331 | }
|
| 332 |
|
| 333 | static inline void *cec_get_drvdata(const struct cec_adapter *adap)
|
| 334 | {
|
| 335 | return adap->priv;
|
| 336 | }
|
| 337 |
|
| 338 | static inline bool cec_has_log_addr(const struct cec_adapter *adap, u8 log_addr)
|
| 339 | {
|
| 340 | return adap->log_addrs.log_addr_mask & (1 << log_addr);
|
| 341 | }
|
| 342 |
|
| 343 | static inline bool cec_is_sink(const struct cec_adapter *adap)
|
| 344 | {
|
| 345 | return adap->phys_addr == 0;
|
| 346 | }
|
| 347 |
|
| 348 | |
| 349 | * cec_is_registered() - is the CEC adapter registered?
|
| 350 | *
|
| 351 | * @adap: the CEC adapter, may be NULL.
|
| 352 | *
|
| 353 | * Return: true if the adapter is registered, false otherwise.
|
| 354 |
|
| 355 | static inline bool cec_is_registered(const struct cec_adapter *adap)
|
| 356 | {
|
| 357 | return adap && adap->devnode.registered;
|
| 358 | }
|
| 359 |
|
| 360 | #define cec_phys_addr_exp(pa) \
|
| 361 | ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf
|
| 362 |
|
| 363 | struct edid;
|
| 364 | struct drm_connector;
|
| 365 |
|
| 366 | #if IS_REACHABLE(CONFIG_CEC_CORE)
|
| 367 | struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
| 368 | void *priv, const char *name, u32 caps, u8 available_las);
|
| 369 | int cec_register_adapter(struct cec_adapter *adap, struct device *parent);
|
| 370 | void cec_unregister_adapter(struct cec_adapter *adap);
|
| 371 | void cec_delete_adapter(struct cec_adapter *adap);
|
| 372 |
|
| 373 | int cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs,
|
| 374 | bool block);
|
| 375 | void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
|
| 376 | bool block);
|
| 377 | void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
|
| 378 | const struct edid *edid);
|
| 379 | void cec_s_conn_info(struct cec_adapter *adap,
|
| 380 | const struct cec_connector_info *conn_info);
|
| 381 | int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
|
| 382 | bool block);
|
| 383 |
|
| 384 |
|
| 385 | void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
| 386 | u8 arb_lost_cnt, u8 nack_cnt, u8 low_drive_cnt,
|
| 387 | u8 error_cnt, ktime_t ts);
|
| 388 |
|
| 389 | static inline void cec_transmit_done(struct cec_adapter *adap, u8 status,
|
| 390 | u8 arb_lost_cnt, u8 nack_cnt,
|
| 391 | u8 low_drive_cnt, u8 error_cnt)
|
| 392 | {
|
| 393 | cec_transmit_done_ts(adap, status, arb_lost_cnt, nack_cnt,
|
| 394 | low_drive_cnt, error_cnt, ktime_get());
|
| 395 | }
|
| 396 | |
| 397 | * Simplified version of cec_transmit_done for hardware that doesn't retry
|
| 398 | * failed transmits. So this is always just one attempt in which case
|
| 399 | * the status is sufficient.
|
| 400 |
|
| 401 | void cec_transmit_attempt_done_ts(struct cec_adapter *adap,
|
| 402 | u8 status, ktime_t ts);
|
| 403 |
|
| 404 | static inline void cec_transmit_attempt_done(struct cec_adapter *adap,
|
| 405 | u8 status)
|
| 406 | {
|
| 407 | cec_transmit_attempt_done_ts(adap, status, ktime_get());
|
| 408 | }
|
| 409 |
|
| 410 | void cec_received_msg_ts(struct cec_adapter *adap,
|
| 411 | struct cec_msg *msg, ktime_t ts);
|
| 412 |
|
| 413 | static inline void cec_received_msg(struct cec_adapter *adap,
|
| 414 | struct cec_msg *msg)
|
| 415 | {
|
| 416 | cec_received_msg_ts(adap, msg, ktime_get());
|
| 417 | }
|
| 418 |
|
| 419 | |
| 420 | * cec_queue_pin_cec_event() - queue a CEC pin event with a given timestamp.
|
| 421 | *
|
| 422 | * @adap: pointer to the cec adapter
|
| 423 | * @is_high: when true the CEC pin is high, otherwise it is low
|
| 424 | * @dropped_events: when true some events were dropped
|
| 425 | * @ts: the timestamp for this event
|
| 426 | *
|
| 427 |
|
| 428 | void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high,
|
| 429 | bool dropped_events, ktime_t ts);
|
| 430 |
|
| 431 | |
| 432 | * cec_queue_pin_hpd_event() - queue a pin event with a given timestamp.
|
| 433 | *
|
| 434 | * @adap: pointer to the cec adapter
|
| 435 | * @is_high: when true the HPD pin is high, otherwise it is low
|
| 436 | * @ts: the timestamp for this event
|
| 437 | *
|
| 438 |
|
| 439 | void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts);
|
| 440 |
|
| 441 | |
| 442 | * cec_queue_pin_5v_event() - queue a pin event with a given timestamp.
|
| 443 | *
|
| 444 | * @adap: pointer to the cec adapter
|
| 445 | * @is_high: when true the 5V pin is high, otherwise it is low
|
| 446 | * @ts: the timestamp for this event
|
| 447 | *
|
| 448 |
|
| 449 | void cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts);
|
| 450 |
|
| 451 | |
| 452 | * cec_get_edid_phys_addr() - find and return the physical address
|
| 453 | *
|
| 454 | * @edid: pointer to the EDID data
|
| 455 | * @size: size in bytes of the EDID data
|
| 456 | * @offset: If not %NULL then the location of the physical address
|
| 457 | * bytes in the EDID will be returned here. This is set to 0
|
| 458 | * if there is no physical address found.
|
| 459 | *
|
| 460 | * Return: the physical address or CEC_PHYS_ADDR_INVALID if there is none.
|
| 461 |
|
| 462 | u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
|
| 463 | unsigned int *offset);
|
| 464 |
|
| 465 | void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info,
|
| 466 | const struct drm_connector *connector);
|
| 467 |
|
| 468 | #else
|
| 469 |
|
| 470 | static inline int cec_register_adapter(struct cec_adapter *adap,
|
| 471 | struct device *parent)
|
| 472 | {
|
| 473 | return 0;
|
| 474 | }
|
| 475 |
|
| 476 | static inline void cec_unregister_adapter(struct cec_adapter *adap)
|
| 477 | {
|
| 478 | }
|
| 479 |
|
| 480 | static inline void cec_delete_adapter(struct cec_adapter *adap)
|
| 481 | {
|
| 482 | }
|
| 483 |
|
| 484 | static inline void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
|
| 485 | bool block)
|
| 486 | {
|
| 487 | }
|
| 488 |
|
| 489 | static inline void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
|
| 490 | const struct edid *edid)
|
| 491 | {
|
| 492 | }
|
| 493 |
|
| 494 | static inline u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
|
| 495 | unsigned int *offset)
|
| 496 | {
|
| 497 | if (offset)
|
| 498 | *offset = 0;
|
| 499 | return CEC_PHYS_ADDR_INVALID;
|
| 500 | }
|
| 501 |
|
| 502 | static inline void cec_s_conn_info(struct cec_adapter *adap,
|
| 503 | const struct cec_connector_info *conn_info)
|
| 504 | {
|
| 505 | }
|
| 506 |
|
| 507 | static inline void
|
| 508 | cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info,
|
| 509 | const struct drm_connector *connector)
|
| 510 | {
|
| 511 | memset(conn_info, 0, sizeof(*conn_info));
|
| 512 | }
|
| 513 |
|
| 514 | #endif
|
| 515 |
|
| 516 | |
| 517 | * cec_phys_addr_invalidate() - set the physical address to INVALID
|
| 518 | *
|
| 519 | * @adap: the CEC adapter
|
| 520 | *
|
| 521 | * This is a simple helper function to invalidate the physical
|
| 522 | * address.
|
| 523 |
|
| 524 | static inline void cec_phys_addr_invalidate(struct cec_adapter *adap)
|
| 525 | {
|
| 526 | cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false);
|
| 527 | }
|
| 528 |
|
| 529 | |
| 530 | * cec_get_edid_spa_location() - find location of the Source Physical Address
|
| 531 | *
|
| 532 | * @edid: the EDID
|
| 533 | * @size: the size of the EDID
|
| 534 | *
|
| 535 | * This EDID is expected to be a CEA-861 compliant, which means that there are
|
| 536 | * at least two blocks and one or more of the extensions blocks are CEA-861
|
| 537 | * blocks.
|
| 538 | *
|
| 539 | * The returned location is guaranteed to be <= size-2.
|
| 540 | *
|
| 541 | * This is an inline function since it is used by both CEC and V4L2.
|
| 542 | * Ideally this would go in a module shared by both, but it is overkill to do
|
| 543 | * that for just a single function.
|
| 544 |
|
| 545 | static inline unsigned int cec_get_edid_spa_location(const u8 *edid,
|
| 546 | unsigned int size)
|
| 547 | {
|
| 548 | unsigned int blocks = size / 128;
|
| 549 | unsigned int block;
|
| 550 | u8 d;
|
| 551 |
|
| 552 |
|
| 553 | if (blocks < 2 || size % 128)
|
| 554 | return 0;
|
| 555 |
|
| 556 | |
| 557 | * If there are fewer extension blocks than the size, then update
|
| 558 | * 'blocks'. It is allowed to have more extension blocks than the size,
|
| 559 | * since some hardware can only read e.g. 256 bytes of the EDID, even
|
| 560 | * though more blocks are present. The first CEA-861 extension block
|
| 561 | * should normally be in block 1 anyway.
|
| 562 |
|
| 563 | if (edid[0x7e] + 1 < blocks)
|
| 564 | blocks = edid[0x7e] + 1;
|
| 565 |
|
| 566 | for (block = 1; block < blocks; block++) {
|
| 567 | unsigned int offset = block * 128;
|
| 568 |
|
| 569 |
|
| 570 | if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
|
| 571 | continue;
|
| 572 |
|
| 573 |
|
| 574 | d = edid[offset + 2] & 0x7f;
|
| 575 |
|
| 576 | if (d <= 4)
|
| 577 | continue;
|
| 578 | if (d > 4) {
|
| 579 | unsigned int i = offset + 4;
|
| 580 | unsigned int end = offset + d;
|
| 581 |
|
| 582 |
|
| 583 | do {
|
| 584 | u8 tag = edid[i] >> 5;
|
| 585 | u8 len = edid[i] & 0x1f;
|
| 586 |
|
| 587 | if (tag == 3 && len >= 5 && i + len <= end &&
|
| 588 | edid[i + 1] == 0x03 &&
|
| 589 | edid[i + 2] == 0x0c &&
|
| 590 | edid[i + 3] == 0x00)
|
| 591 | return i + 4;
|
| 592 | i += len + 1;
|
| 593 | } while (i < end);
|
| 594 | }
|
| 595 | }
|
| 596 | return 0;
|
| 597 | }
|
| 598 |
|
| 599 | #endif
|