linux/drivers/media/cec/core/cec-adap.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter
 *
 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
 */

#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/ktime.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/types.h>

#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
#include <drm/drm_file.h>

#include "cec-priv.h"

static void cec_fill_msg_report_features(struct cec_adapter *adap,
					 struct cec_msg *msg,
					 unsigned int la_idx);

static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr)
{}

static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr)
{}

u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
			   unsigned int *offset)
{}
EXPORT_SYMBOL_GPL();

void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info,
				 const struct drm_connector *connector)
{}
EXPORT_SYMBOL_GPL();

/*
 * Queue a new event for this filehandle. If ts == 0, then set it
 * to the current time.
 *
 * We keep a queue of at most max_event events where max_event differs
 * per event. If the queue becomes full, then drop the oldest event and
 * keep track of how many events we've dropped.
 */
void cec_queue_event_fh(struct cec_fh *fh,
			const struct cec_event *new_ev, u64 ts)
{}

/* Queue a new event for all open filehandles. */
static void cec_queue_event(struct cec_adapter *adap,
			    const struct cec_event *ev)
{}

/* Notify userspace that the CEC pin changed state at the given time. */
void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high,
			     bool dropped_events, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

/* Notify userspace that the HPD pin changed state at the given time. */
void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

/* Notify userspace that the 5V pin changed state at the given time. */
void cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

/*
 * Queue a new message for this filehandle.
 *
 * We keep a queue of at most CEC_MAX_MSG_RX_QUEUE_SZ messages. If the
 * queue becomes full, then drop the oldest message and keep track
 * of how many messages we've dropped.
 */
static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg)
{}

/*
 * Queue the message for those filehandles that are in monitor mode.
 * If valid_la is true (this message is for us or was sent by us),
 * then pass it on to any monitoring filehandle. If this message
 * isn't for us or from us, then only give it to filehandles that
 * are in MONITOR_ALL mode.
 *
 * This can only happen if the CEC_CAP_MONITOR_ALL capability is
 * set and the CEC adapter was placed in 'monitor all' mode.
 */
static void cec_queue_msg_monitor(struct cec_adapter *adap,
				  const struct cec_msg *msg,
				  bool valid_la)
{}

/*
 * Queue the message for follower filehandles.
 */
static void cec_queue_msg_followers(struct cec_adapter *adap,
				    const struct cec_msg *msg)
{}

/* Notify userspace of an adapter state change. */
static void cec_post_state_event(struct cec_adapter *adap)
{}

/*
 * A CEC transmit (and a possible wait for reply) completed.
 * If this was in blocking mode, then complete it, otherwise
 * queue the message for userspace to dequeue later.
 *
 * This function is called with adap->lock held.
 */
static void cec_data_completed(struct cec_data *data)
{}

/*
 * A pending CEC transmit needs to be cancelled, either because the CEC
 * adapter is disabled or the transmit takes an impossibly long time to
 * finish, or the reply timed out.
 *
 * This function is called with adap->lock held.
 */
static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status)
{}

/*
 * Flush all pending transmits and cancel any pending timeout work.
 *
 * This function is called with adap->lock held.
 */
static void cec_flush(struct cec_adapter *adap)
{}

/*
 * Main CEC state machine
 *
 * Wait until the thread should be stopped, or we are not transmitting and
 * a new transmit message is queued up, in which case we start transmitting
 * that message. When the adapter finished transmitting the message it will
 * call cec_transmit_done().
 *
 * If the adapter is disabled, then remove all queued messages instead.
 *
 * If the current transmit times out, then cancel that transmit.
 */
int cec_thread_func(void *_adap)
{}

/*
 * Called by the CEC adapter if a transmit finished.
 */
void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
			  u8 arb_lost_cnt, u8 nack_cnt, u8 low_drive_cnt,
			  u8 error_cnt, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

void cec_transmit_attempt_done_ts(struct cec_adapter *adap,
				  u8 status, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

/*
 * Called when waiting for a reply times out.
 */
static void cec_wait_timeout(struct work_struct *work)
{}

/*
 * Transmit a message. The fh argument may be NULL if the transmit is not
 * associated with a specific filehandle.
 *
 * This function is called with adap->lock held.
 */
int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
			struct cec_fh *fh, bool block)
{}

/* Helper function to be used by drivers and this framework. */
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
		     bool block)
{}
EXPORT_SYMBOL_GPL();

/*
 * I don't like forward references but without this the low-level
 * cec_received_msg() function would come after a bunch of high-level
 * CEC protocol handling functions. That was very confusing.
 */
static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
			      bool is_reply);

#define DIRECTED
#define BCAST1_4
#define BCAST2_0
#define BCAST
#define BOTH

/*
 * Specify minimum length and whether the message is directed, broadcast
 * or both. Messages that do not match the criteria are ignored as per
 * the CEC specification.
 */
static const u8 cec_msg_size[256] =;

/* Called by the CEC adapter if a message is received */
void cec_received_msg_ts(struct cec_adapter *adap,
			 struct cec_msg *msg, ktime_t ts)
{}
EXPORT_SYMBOL_GPL();

/* Logical Address Handling */

/*
 * Attempt to claim a specific logical address.
 *
 * This function is called with adap->lock held.
 */
static int cec_config_log_addr(struct cec_adapter *adap,
			       unsigned int idx,
			       unsigned int log_addr)
{}

/*
 * Unconfigure the adapter: clear all logical addresses and send
 * the state changed event.
 *
 * This function is called with adap->lock held.
 */
static void cec_adap_unconfigure(struct cec_adapter *adap)
{}

/*
 * Attempt to claim the required logical addresses.
 */
static int cec_config_thread_func(void *arg)
{}

/*
 * Called from either __cec_s_phys_addr or __cec_s_log_addrs to claim the
 * logical addresses.
 *
 * This function is called with adap->lock held.
 */
static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
{}

/*
 * Helper function to enable/disable the CEC adapter.
 *
 * This function is called with adap->lock held.
 */
int cec_adap_enable(struct cec_adapter *adap)
{}

/* Set a new physical address and send an event notifying userspace of this.
 *
 * This function is called with adap->lock held.
 */
void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
{}

void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
{}
EXPORT_SYMBOL_GPL();

/*
 * Note: In the drm subsystem, prefer calling (if possible):
 *
 * cec_s_phys_addr(adap, connector->display_info.source_physical_address, false);
 */
void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
			       const struct edid *edid)
{}
EXPORT_SYMBOL_GPL();

void cec_s_conn_info(struct cec_adapter *adap,
		     const struct cec_connector_info *conn_info)
{}
EXPORT_SYMBOL_GPL();

/*
 * Called from either the ioctl or a driver to set the logical addresses.
 *
 * This function is called with adap->lock held.
 */
int __cec_s_log_addrs(struct cec_adapter *adap,
		      struct cec_log_addrs *log_addrs, bool block)
{}

int cec_s_log_addrs(struct cec_adapter *adap,
		    struct cec_log_addrs *log_addrs, bool block)
{}
EXPORT_SYMBOL_GPL();

/* High-level core CEC message handling */

/* Fill in the Report Features message */
static void cec_fill_msg_report_features(struct cec_adapter *adap,
					 struct cec_msg *msg,
					 unsigned int la_idx)
{}

/* Transmit the Feature Abort message */
static int cec_feature_abort_reason(struct cec_adapter *adap,
				    struct cec_msg *msg, u8 reason)
{}

static int cec_feature_abort(struct cec_adapter *adap, struct cec_msg *msg)
{}

static int cec_feature_refused(struct cec_adapter *adap, struct cec_msg *msg)
{}

/*
 * Called when a CEC message is received. This function will do any
 * necessary core processing. The is_reply bool is true if this message
 * is a reply to an earlier transmit.
 *
 * The message is either a broadcast message or a valid directed message.
 */
static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
			      bool is_reply)
{}

/*
 * Helper functions to keep track of the 'monitor all' use count.
 *
 * These functions are called with adap->lock held.
 */
int cec_monitor_all_cnt_inc(struct cec_adapter *adap)
{}

void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
{}

/*
 * Helper functions to keep track of the 'monitor pin' use count.
 *
 * These functions are called with adap->lock held.
 */
int cec_monitor_pin_cnt_inc(struct cec_adapter *adap)
{}

void cec_monitor_pin_cnt_dec(struct cec_adapter *adap)
{}

#ifdef CONFIG_DEBUG_FS
/*
 * Log the current state of the CEC adapter.
 * Very useful for debugging.
 */
int cec_adap_status(struct seq_file *file, void *priv)
{}
#endif