162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cec - HDMI Consumer Electronics Control support header 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _MEDIA_CEC_H 962306a36Sopenharmony_ci#define _MEDIA_CEC_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/poll.h> 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/debugfs.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/cdev.h> 1662306a36Sopenharmony_ci#include <linux/kthread.h> 1762306a36Sopenharmony_ci#include <linux/timer.h> 1862306a36Sopenharmony_ci#include <linux/cec-funcs.h> 1962306a36Sopenharmony_ci#include <media/rc-core.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define CEC_CAP_DEFAULTS (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | \ 2262306a36Sopenharmony_ci CEC_CAP_PASSTHROUGH | CEC_CAP_RC) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/** 2562306a36Sopenharmony_ci * struct cec_devnode - cec device node 2662306a36Sopenharmony_ci * @dev: cec device 2762306a36Sopenharmony_ci * @cdev: cec character device 2862306a36Sopenharmony_ci * @minor: device node minor number 2962306a36Sopenharmony_ci * @lock: lock to serialize open/release and registration 3062306a36Sopenharmony_ci * @registered: the device was correctly registered 3162306a36Sopenharmony_ci * @unregistered: the device was unregistered 3262306a36Sopenharmony_ci * @lock_fhs: lock to control access to @fhs 3362306a36Sopenharmony_ci * @fhs: the list of open filehandles (cec_fh) 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * This structure represents a cec-related device node. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * To add or remove filehandles from @fhs the @lock must be taken first, 3862306a36Sopenharmony_ci * followed by @lock_fhs. It is safe to access @fhs if either lock is held. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * The @parent is a physical device. It must be set by core or device drivers 4162306a36Sopenharmony_ci * before registering the node. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistruct cec_devnode { 4462306a36Sopenharmony_ci /* sysfs */ 4562306a36Sopenharmony_ci struct device dev; 4662306a36Sopenharmony_ci struct cdev cdev; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* device info */ 4962306a36Sopenharmony_ci int minor; 5062306a36Sopenharmony_ci /* serialize open/release and registration */ 5162306a36Sopenharmony_ci struct mutex lock; 5262306a36Sopenharmony_ci bool registered; 5362306a36Sopenharmony_ci bool unregistered; 5462306a36Sopenharmony_ci /* protect access to fhs */ 5562306a36Sopenharmony_ci struct mutex lock_fhs; 5662306a36Sopenharmony_ci struct list_head fhs; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct cec_adapter; 6062306a36Sopenharmony_cistruct cec_data; 6162306a36Sopenharmony_cistruct cec_pin; 6262306a36Sopenharmony_cistruct cec_notifier; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct cec_data { 6562306a36Sopenharmony_ci struct list_head list; 6662306a36Sopenharmony_ci struct list_head xfer_list; 6762306a36Sopenharmony_ci struct cec_adapter *adap; 6862306a36Sopenharmony_ci struct cec_msg msg; 6962306a36Sopenharmony_ci struct cec_fh *fh; 7062306a36Sopenharmony_ci struct delayed_work work; 7162306a36Sopenharmony_ci struct completion c; 7262306a36Sopenharmony_ci u8 attempts; 7362306a36Sopenharmony_ci bool blocking; 7462306a36Sopenharmony_ci bool completed; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct cec_msg_entry { 7862306a36Sopenharmony_ci struct list_head list; 7962306a36Sopenharmony_ci struct cec_msg msg; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct cec_event_entry { 8362306a36Sopenharmony_ci struct list_head list; 8462306a36Sopenharmony_ci struct cec_event ev; 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define CEC_NUM_CORE_EVENTS 2 8862306a36Sopenharmony_ci#define CEC_NUM_EVENTS CEC_EVENT_PIN_5V_HIGH 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct cec_fh { 9162306a36Sopenharmony_ci struct list_head list; 9262306a36Sopenharmony_ci struct list_head xfer_list; 9362306a36Sopenharmony_ci struct cec_adapter *adap; 9462306a36Sopenharmony_ci u8 mode_initiator; 9562306a36Sopenharmony_ci u8 mode_follower; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Events */ 9862306a36Sopenharmony_ci wait_queue_head_t wait; 9962306a36Sopenharmony_ci struct mutex lock; 10062306a36Sopenharmony_ci struct list_head events[CEC_NUM_EVENTS]; /* queued events */ 10162306a36Sopenharmony_ci u16 queued_events[CEC_NUM_EVENTS]; 10262306a36Sopenharmony_ci unsigned int total_queued_events; 10362306a36Sopenharmony_ci struct cec_event_entry core_events[CEC_NUM_CORE_EVENTS]; 10462306a36Sopenharmony_ci struct list_head msgs; /* queued messages */ 10562306a36Sopenharmony_ci unsigned int queued_msgs; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define CEC_SIGNAL_FREE_TIME_RETRY 3 10962306a36Sopenharmony_ci#define CEC_SIGNAL_FREE_TIME_NEW_INITIATOR 5 11062306a36Sopenharmony_ci#define CEC_SIGNAL_FREE_TIME_NEXT_XFER 7 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* The nominal data bit period is 2.4 ms */ 11362306a36Sopenharmony_ci#define CEC_FREE_TIME_TO_USEC(ft) ((ft) * 2400) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistruct cec_adap_ops { 11662306a36Sopenharmony_ci /* Low-level callbacks, called with adap->lock held */ 11762306a36Sopenharmony_ci int (*adap_enable)(struct cec_adapter *adap, bool enable); 11862306a36Sopenharmony_ci int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); 11962306a36Sopenharmony_ci int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable); 12062306a36Sopenharmony_ci int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); 12162306a36Sopenharmony_ci void (*adap_unconfigured)(struct cec_adapter *adap); 12262306a36Sopenharmony_ci int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, 12362306a36Sopenharmony_ci u32 signal_free_time, struct cec_msg *msg); 12462306a36Sopenharmony_ci void (*adap_nb_transmit_canceled)(struct cec_adapter *adap, 12562306a36Sopenharmony_ci const struct cec_msg *msg); 12662306a36Sopenharmony_ci void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); 12762306a36Sopenharmony_ci void (*adap_free)(struct cec_adapter *adap); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Error injection callbacks, called without adap->lock held */ 13062306a36Sopenharmony_ci int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); 13162306a36Sopenharmony_ci bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* High-level CEC message callback, called without adap->lock held */ 13462306a36Sopenharmony_ci void (*configured)(struct cec_adapter *adap); 13562306a36Sopenharmony_ci int (*received)(struct cec_adapter *adap, struct cec_msg *msg); 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * The minimum message length you can receive (excepting poll messages) is 2. 14062306a36Sopenharmony_ci * With a transfer rate of at most 36 bytes per second this makes 18 messages 14162306a36Sopenharmony_ci * per second worst case. 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * We queue at most 3 seconds worth of received messages. The CEC specification 14462306a36Sopenharmony_ci * requires that messages are replied to within a second, so 3 seconds should 14562306a36Sopenharmony_ci * give more than enough margin. Since most messages are actually more than 2 14662306a36Sopenharmony_ci * bytes, this is in practice a lot more than 3 seconds. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci#define CEC_MAX_MSG_RX_QUEUE_SZ (18 * 3) 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci * The transmit queue is limited to 1 second worth of messages (worst case). 15262306a36Sopenharmony_ci * Messages can be transmitted by userspace and kernel space. But for both it 15362306a36Sopenharmony_ci * makes no sense to have a lot of messages queued up. One second seems 15462306a36Sopenharmony_ci * reasonable. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci#define CEC_MAX_MSG_TX_QUEUE_SZ (18 * 1) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/** 15962306a36Sopenharmony_ci * struct cec_adapter - cec adapter structure 16062306a36Sopenharmony_ci * @owner: module owner 16162306a36Sopenharmony_ci * @name: name of the CEC adapter 16262306a36Sopenharmony_ci * @devnode: device node for the /dev/cecX device 16362306a36Sopenharmony_ci * @lock: mutex controlling access to this structure 16462306a36Sopenharmony_ci * @rc: remote control device 16562306a36Sopenharmony_ci * @transmit_queue: queue of pending transmits 16662306a36Sopenharmony_ci * @transmit_queue_sz: number of pending transmits 16762306a36Sopenharmony_ci * @wait_queue: queue of transmits waiting for a reply 16862306a36Sopenharmony_ci * @transmitting: CEC messages currently being transmitted 16962306a36Sopenharmony_ci * @transmit_in_progress: true if a transmit is in progress 17062306a36Sopenharmony_ci * @transmit_in_progress_aborted: true if a transmit is in progress is to be 17162306a36Sopenharmony_ci * aborted. This happens if the logical address is 17262306a36Sopenharmony_ci * invalidated while the transmit is ongoing. In that 17362306a36Sopenharmony_ci * case the transmit will finish, but will not retransmit 17462306a36Sopenharmony_ci * and be marked as ABORTED. 17562306a36Sopenharmony_ci * @xfer_timeout_ms: the transfer timeout in ms. 17662306a36Sopenharmony_ci * If 0, then timeout after 2.1 ms. 17762306a36Sopenharmony_ci * @kthread_config: kthread used to configure a CEC adapter 17862306a36Sopenharmony_ci * @config_completion: used to signal completion of the config kthread 17962306a36Sopenharmony_ci * @kthread: main CEC processing thread 18062306a36Sopenharmony_ci * @kthread_waitq: main CEC processing wait_queue 18162306a36Sopenharmony_ci * @ops: cec adapter ops 18262306a36Sopenharmony_ci * @priv: cec driver's private data 18362306a36Sopenharmony_ci * @capabilities: cec adapter capabilities 18462306a36Sopenharmony_ci * @available_log_addrs: maximum number of available logical addresses 18562306a36Sopenharmony_ci * @phys_addr: the current physical address 18662306a36Sopenharmony_ci * @needs_hpd: if true, then the HDMI HotPlug Detect pin must be high 18762306a36Sopenharmony_ci * in order to transmit or receive CEC messages. This is usually a HW 18862306a36Sopenharmony_ci * limitation. 18962306a36Sopenharmony_ci * @is_enabled: the CEC adapter is enabled 19062306a36Sopenharmony_ci * @is_configuring: the CEC adapter is configuring (i.e. claiming LAs) 19162306a36Sopenharmony_ci * @must_reconfigure: while configuring, the PA changed, so reclaim LAs 19262306a36Sopenharmony_ci * @is_configured: the CEC adapter is configured (i.e. has claimed LAs) 19362306a36Sopenharmony_ci * @cec_pin_is_high: if true then the CEC pin is high. Only used with the 19462306a36Sopenharmony_ci * CEC pin framework. 19562306a36Sopenharmony_ci * @adap_controls_phys_addr: if true, then the CEC adapter controls the 19662306a36Sopenharmony_ci * physical address, i.e. the CEC hardware can detect HPD changes and 19762306a36Sopenharmony_ci * read the EDID and is not dependent on an external HDMI driver. 19862306a36Sopenharmony_ci * Drivers that need this can set this field to true after the 19962306a36Sopenharmony_ci * cec_allocate_adapter() call. 20062306a36Sopenharmony_ci * @last_initiator: the initiator of the last transmitted message. 20162306a36Sopenharmony_ci * @monitor_all_cnt: number of filehandles monitoring all msgs 20262306a36Sopenharmony_ci * @monitor_pin_cnt: number of filehandles monitoring pin changes 20362306a36Sopenharmony_ci * @follower_cnt: number of filehandles in follower mode 20462306a36Sopenharmony_ci * @cec_follower: filehandle of the exclusive follower 20562306a36Sopenharmony_ci * @cec_initiator: filehandle of the exclusive initiator 20662306a36Sopenharmony_ci * @passthrough: if true, then the exclusive follower is in 20762306a36Sopenharmony_ci * passthrough mode. 20862306a36Sopenharmony_ci * @log_addrs: current logical addresses 20962306a36Sopenharmony_ci * @conn_info: current connector info 21062306a36Sopenharmony_ci * @tx_timeouts: number of transmit timeouts 21162306a36Sopenharmony_ci * @notifier: CEC notifier 21262306a36Sopenharmony_ci * @pin: CEC pin status struct 21362306a36Sopenharmony_ci * @cec_dir: debugfs cec directory 21462306a36Sopenharmony_ci * @status_file: debugfs cec status file 21562306a36Sopenharmony_ci * @error_inj_file: debugfs cec error injection file 21662306a36Sopenharmony_ci * @sequence: transmit sequence counter 21762306a36Sopenharmony_ci * @input_phys: remote control input_phys name 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * This structure represents a cec adapter. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistruct cec_adapter { 22262306a36Sopenharmony_ci struct module *owner; 22362306a36Sopenharmony_ci char name[32]; 22462306a36Sopenharmony_ci struct cec_devnode devnode; 22562306a36Sopenharmony_ci struct mutex lock; 22662306a36Sopenharmony_ci struct rc_dev *rc; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci struct list_head transmit_queue; 22962306a36Sopenharmony_ci unsigned int transmit_queue_sz; 23062306a36Sopenharmony_ci struct list_head wait_queue; 23162306a36Sopenharmony_ci struct cec_data *transmitting; 23262306a36Sopenharmony_ci bool transmit_in_progress; 23362306a36Sopenharmony_ci bool transmit_in_progress_aborted; 23462306a36Sopenharmony_ci unsigned int xfer_timeout_ms; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci struct task_struct *kthread_config; 23762306a36Sopenharmony_ci struct completion config_completion; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci struct task_struct *kthread; 24062306a36Sopenharmony_ci wait_queue_head_t kthread_waitq; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci const struct cec_adap_ops *ops; 24362306a36Sopenharmony_ci void *priv; 24462306a36Sopenharmony_ci u32 capabilities; 24562306a36Sopenharmony_ci u8 available_log_addrs; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci u16 phys_addr; 24862306a36Sopenharmony_ci bool needs_hpd; 24962306a36Sopenharmony_ci bool is_enabled; 25062306a36Sopenharmony_ci bool is_configuring; 25162306a36Sopenharmony_ci bool must_reconfigure; 25262306a36Sopenharmony_ci bool is_configured; 25362306a36Sopenharmony_ci bool cec_pin_is_high; 25462306a36Sopenharmony_ci bool adap_controls_phys_addr; 25562306a36Sopenharmony_ci u8 last_initiator; 25662306a36Sopenharmony_ci u32 monitor_all_cnt; 25762306a36Sopenharmony_ci u32 monitor_pin_cnt; 25862306a36Sopenharmony_ci u32 follower_cnt; 25962306a36Sopenharmony_ci struct cec_fh *cec_follower; 26062306a36Sopenharmony_ci struct cec_fh *cec_initiator; 26162306a36Sopenharmony_ci bool passthrough; 26262306a36Sopenharmony_ci struct cec_log_addrs log_addrs; 26362306a36Sopenharmony_ci struct cec_connector_info conn_info; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci u32 tx_timeouts; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci#ifdef CONFIG_CEC_NOTIFIER 26862306a36Sopenharmony_ci struct cec_notifier *notifier; 26962306a36Sopenharmony_ci#endif 27062306a36Sopenharmony_ci#ifdef CONFIG_CEC_PIN 27162306a36Sopenharmony_ci struct cec_pin *pin; 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci struct dentry *cec_dir; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci u32 sequence; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci char input_phys[32]; 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic inline void *cec_get_drvdata(const struct cec_adapter *adap) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci return adap->priv; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic inline bool cec_has_log_addr(const struct cec_adapter *adap, u8 log_addr) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci return adap->log_addrs.log_addr_mask & (1 << log_addr); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic inline bool cec_is_sink(const struct cec_adapter *adap) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci return adap->phys_addr == 0; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/** 29762306a36Sopenharmony_ci * cec_is_registered() - is the CEC adapter registered? 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * @adap: the CEC adapter, may be NULL. 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * Return: true if the adapter is registered, false otherwise. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_cistatic inline bool cec_is_registered(const struct cec_adapter *adap) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci return adap && adap->devnode.registered; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci#define cec_phys_addr_exp(pa) \ 30962306a36Sopenharmony_ci ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistruct edid; 31262306a36Sopenharmony_cistruct drm_connector; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_CEC_CORE) 31562306a36Sopenharmony_cistruct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, 31662306a36Sopenharmony_ci void *priv, const char *name, u32 caps, u8 available_las); 31762306a36Sopenharmony_ciint cec_register_adapter(struct cec_adapter *adap, struct device *parent); 31862306a36Sopenharmony_civoid cec_unregister_adapter(struct cec_adapter *adap); 31962306a36Sopenharmony_civoid cec_delete_adapter(struct cec_adapter *adap); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciint cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs, 32262306a36Sopenharmony_ci bool block); 32362306a36Sopenharmony_civoid cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, 32462306a36Sopenharmony_ci bool block); 32562306a36Sopenharmony_civoid cec_s_phys_addr_from_edid(struct cec_adapter *adap, 32662306a36Sopenharmony_ci const struct edid *edid); 32762306a36Sopenharmony_civoid cec_s_conn_info(struct cec_adapter *adap, 32862306a36Sopenharmony_ci const struct cec_connector_info *conn_info); 32962306a36Sopenharmony_ciint cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, 33062306a36Sopenharmony_ci bool block); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* Called by the adapter */ 33362306a36Sopenharmony_civoid cec_transmit_done_ts(struct cec_adapter *adap, u8 status, 33462306a36Sopenharmony_ci u8 arb_lost_cnt, u8 nack_cnt, u8 low_drive_cnt, 33562306a36Sopenharmony_ci u8 error_cnt, ktime_t ts); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic inline void cec_transmit_done(struct cec_adapter *adap, u8 status, 33862306a36Sopenharmony_ci u8 arb_lost_cnt, u8 nack_cnt, 33962306a36Sopenharmony_ci u8 low_drive_cnt, u8 error_cnt) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci cec_transmit_done_ts(adap, status, arb_lost_cnt, nack_cnt, 34262306a36Sopenharmony_ci low_drive_cnt, error_cnt, ktime_get()); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci/* 34562306a36Sopenharmony_ci * Simplified version of cec_transmit_done for hardware that doesn't retry 34662306a36Sopenharmony_ci * failed transmits. So this is always just one attempt in which case 34762306a36Sopenharmony_ci * the status is sufficient. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_civoid cec_transmit_attempt_done_ts(struct cec_adapter *adap, 35062306a36Sopenharmony_ci u8 status, ktime_t ts); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic inline void cec_transmit_attempt_done(struct cec_adapter *adap, 35362306a36Sopenharmony_ci u8 status) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci cec_transmit_attempt_done_ts(adap, status, ktime_get()); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_civoid cec_received_msg_ts(struct cec_adapter *adap, 35962306a36Sopenharmony_ci struct cec_msg *msg, ktime_t ts); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic inline void cec_received_msg(struct cec_adapter *adap, 36262306a36Sopenharmony_ci struct cec_msg *msg) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci cec_received_msg_ts(adap, msg, ktime_get()); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/** 36862306a36Sopenharmony_ci * cec_queue_pin_cec_event() - queue a CEC pin event with a given timestamp. 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * @adap: pointer to the cec adapter 37162306a36Sopenharmony_ci * @is_high: when true the CEC pin is high, otherwise it is low 37262306a36Sopenharmony_ci * @dropped_events: when true some events were dropped 37362306a36Sopenharmony_ci * @ts: the timestamp for this event 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_civoid cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, 37762306a36Sopenharmony_ci bool dropped_events, ktime_t ts); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/** 38062306a36Sopenharmony_ci * cec_queue_pin_hpd_event() - queue a pin event with a given timestamp. 38162306a36Sopenharmony_ci * 38262306a36Sopenharmony_ci * @adap: pointer to the cec adapter 38362306a36Sopenharmony_ci * @is_high: when true the HPD pin is high, otherwise it is low 38462306a36Sopenharmony_ci * @ts: the timestamp for this event 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_civoid cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/** 39062306a36Sopenharmony_ci * cec_queue_pin_5v_event() - queue a pin event with a given timestamp. 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * @adap: pointer to the cec adapter 39362306a36Sopenharmony_ci * @is_high: when true the 5V pin is high, otherwise it is low 39462306a36Sopenharmony_ci * @ts: the timestamp for this event 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_civoid cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/** 40062306a36Sopenharmony_ci * cec_get_edid_phys_addr() - find and return the physical address 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * @edid: pointer to the EDID data 40362306a36Sopenharmony_ci * @size: size in bytes of the EDID data 40462306a36Sopenharmony_ci * @offset: If not %NULL then the location of the physical address 40562306a36Sopenharmony_ci * bytes in the EDID will be returned here. This is set to 0 40662306a36Sopenharmony_ci * if there is no physical address found. 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * Return: the physical address or CEC_PHYS_ADDR_INVALID if there is none. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ciu16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, 41162306a36Sopenharmony_ci unsigned int *offset); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_civoid cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, 41462306a36Sopenharmony_ci const struct drm_connector *connector); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci#else 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic inline int cec_register_adapter(struct cec_adapter *adap, 41962306a36Sopenharmony_ci struct device *parent) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic inline void cec_unregister_adapter(struct cec_adapter *adap) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic inline void cec_delete_adapter(struct cec_adapter *adap) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic inline void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, 43362306a36Sopenharmony_ci bool block) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic inline void cec_s_phys_addr_from_edid(struct cec_adapter *adap, 43862306a36Sopenharmony_ci const struct edid *edid) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic inline u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, 44362306a36Sopenharmony_ci unsigned int *offset) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci if (offset) 44662306a36Sopenharmony_ci *offset = 0; 44762306a36Sopenharmony_ci return CEC_PHYS_ADDR_INVALID; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic inline void cec_s_conn_info(struct cec_adapter *adap, 45162306a36Sopenharmony_ci const struct cec_connector_info *conn_info) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic inline void 45662306a36Sopenharmony_cicec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, 45762306a36Sopenharmony_ci const struct drm_connector *connector) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci memset(conn_info, 0, sizeof(*conn_info)); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci#endif 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/** 46562306a36Sopenharmony_ci * cec_phys_addr_invalidate() - set the physical address to INVALID 46662306a36Sopenharmony_ci * 46762306a36Sopenharmony_ci * @adap: the CEC adapter 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * This is a simple helper function to invalidate the physical 47062306a36Sopenharmony_ci * address. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic inline void cec_phys_addr_invalidate(struct cec_adapter *adap) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/** 47862306a36Sopenharmony_ci * cec_get_edid_spa_location() - find location of the Source Physical Address 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * @edid: the EDID 48162306a36Sopenharmony_ci * @size: the size of the EDID 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * This EDID is expected to be a CEA-861 compliant, which means that there are 48462306a36Sopenharmony_ci * at least two blocks and one or more of the extensions blocks are CEA-861 48562306a36Sopenharmony_ci * blocks. 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * The returned location is guaranteed to be <= size-2. 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * This is an inline function since it is used by both CEC and V4L2. 49062306a36Sopenharmony_ci * Ideally this would go in a module shared by both, but it is overkill to do 49162306a36Sopenharmony_ci * that for just a single function. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistatic inline unsigned int cec_get_edid_spa_location(const u8 *edid, 49462306a36Sopenharmony_ci unsigned int size) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci unsigned int blocks = size / 128; 49762306a36Sopenharmony_ci unsigned int block; 49862306a36Sopenharmony_ci u8 d; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Sanity check: at least 2 blocks and a multiple of the block size */ 50162306a36Sopenharmony_ci if (blocks < 2 || size % 128) 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* 50562306a36Sopenharmony_ci * If there are fewer extension blocks than the size, then update 50662306a36Sopenharmony_ci * 'blocks'. It is allowed to have more extension blocks than the size, 50762306a36Sopenharmony_ci * since some hardware can only read e.g. 256 bytes of the EDID, even 50862306a36Sopenharmony_ci * though more blocks are present. The first CEA-861 extension block 50962306a36Sopenharmony_ci * should normally be in block 1 anyway. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci if (edid[0x7e] + 1 < blocks) 51262306a36Sopenharmony_ci blocks = edid[0x7e] + 1; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci for (block = 1; block < blocks; block++) { 51562306a36Sopenharmony_ci unsigned int offset = block * 128; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Skip any non-CEA-861 extension blocks */ 51862306a36Sopenharmony_ci if (edid[offset] != 0x02 || edid[offset + 1] != 0x03) 51962306a36Sopenharmony_ci continue; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* search Vendor Specific Data Block (tag 3) */ 52262306a36Sopenharmony_ci d = edid[offset + 2] & 0x7f; 52362306a36Sopenharmony_ci /* Check if there are Data Blocks */ 52462306a36Sopenharmony_ci if (d <= 4) 52562306a36Sopenharmony_ci continue; 52662306a36Sopenharmony_ci if (d > 4) { 52762306a36Sopenharmony_ci unsigned int i = offset + 4; 52862306a36Sopenharmony_ci unsigned int end = offset + d; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Note: 'end' is always < 'size' */ 53162306a36Sopenharmony_ci do { 53262306a36Sopenharmony_ci u8 tag = edid[i] >> 5; 53362306a36Sopenharmony_ci u8 len = edid[i] & 0x1f; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (tag == 3 && len >= 5 && i + len <= end && 53662306a36Sopenharmony_ci edid[i + 1] == 0x03 && 53762306a36Sopenharmony_ci edid[i + 2] == 0x0c && 53862306a36Sopenharmony_ci edid[i + 3] == 0x00) 53962306a36Sopenharmony_ci return i + 4; 54062306a36Sopenharmony_ci i += len + 1; 54162306a36Sopenharmony_ci } while (i < end); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci#endif /* _MEDIA_CEC_H */ 548