Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/media/cec/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  cec-notifier.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * cec-notifier.c - notify CEC drivers of physical address changes
 *
 * Copyright 2016 Russell King.
 * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
 */


#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/of_platform.h>

#include <media/cec.h>
#include <media/cec-notifier.h>
#include <drm/drm_edid.h>

struct cec_notifier {
 struct mutex lock;
 struct list_head head;
 struct kref kref;
 struct device *hdmi_dev;
 struct cec_connector_info conn_info;
 const char *port_name;
 struct cec_adapter *cec_adap;

 u16 phys_addr;
};

static LIST_HEAD(cec_notifiers);
static DEFINE_MUTEX(cec_notifiers_lock);

/**
 * cec_notifier_get_conn - find or create a new cec_notifier for the given
 * device and connector tuple.
 * @hdmi_dev: device that sends the events.
 * @port_name: the connector name from which the event occurs
 *
 * If a notifier for device @dev already exists, then increase the refcount
 * and return that notifier.
 *
 * If it doesn't exist, then allocate a new notifier struct and return a
 * pointer to that new struct.
 *
 * Return NULL if the memory could not be allocated.
 */

static struct cec_notifier *
cec_notifier_get_conn(struct device *hdmi_dev, const char *port_name)
{
 struct cec_notifier *n;

 mutex_lock(&cec_notifiers_lock);
 list_for_each_entry(n, &cec_notifiers, head) {
  if (n->hdmi_dev == hdmi_dev &&
      (!port_name ||
       (n->port_name && !strcmp(n->port_name, port_name)))) {
   kref_get(&n->kref);
   mutex_unlock(&cec_notifiers_lock);
   return n;
  }
 }
 n = kzalloc(sizeof(*n), GFP_KERNEL);
 if (!n)
  goto unlock;
 n->hdmi_dev = hdmi_dev;
 if (port_name) {
  n->port_name = kstrdup(port_name, GFP_KERNEL);
  if (!n->port_name) {
   kfree(n);
   n = NULL;
   goto unlock;
  }
 }
 n->phys_addr = CEC_PHYS_ADDR_INVALID;

 mutex_init(&n->lock);
 kref_init(&n->kref);
 list_add_tail(&n->head, &cec_notifiers);
unlock:
 mutex_unlock(&cec_notifiers_lock);
 return n;
}

static void cec_notifier_release(struct kref *kref)
{
 struct cec_notifier *n =
  container_of(kref, struct cec_notifier, kref);

 list_del(&n->head);
 kfree(n->port_name);
 kfree(n);
}

static void cec_notifier_put(struct cec_notifier *n)
{
 mutex_lock(&cec_notifiers_lock);
 kref_put(&n->kref, cec_notifier_release);
 mutex_unlock(&cec_notifiers_lock);
}

struct cec_notifier *
cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name,
      const struct cec_connector_info *conn_info)
{
 struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, port_name);

 if (!n)
  return n;

 mutex_lock(&n->lock);
 n->phys_addr = CEC_PHYS_ADDR_INVALID;
 if (conn_info)
  n->conn_info = *conn_info;
 else
  memset(&n->conn_info, 0, sizeof(n->conn_info));
 if (n->cec_adap) {
  if (!n->cec_adap->adap_controls_phys_addr)
   cec_phys_addr_invalidate(n->cec_adap);
  cec_s_conn_info(n->cec_adap, conn_info);
 }
 mutex_unlock(&n->lock);
 return n;
}
EXPORT_SYMBOL_GPL(cec_notifier_conn_register);

void cec_notifier_conn_unregister(struct cec_notifier *n)
{
 if (!n)
  return;

 mutex_lock(&n->lock);
 memset(&n->conn_info, 0, sizeof(n->conn_info));
 n->phys_addr = CEC_PHYS_ADDR_INVALID;
 if (n->cec_adap) {
  if (!n->cec_adap->adap_controls_phys_addr)
   cec_phys_addr_invalidate(n->cec_adap);
  cec_s_conn_info(n->cec_adap, NULL);
 }
 mutex_unlock(&n->lock);
 cec_notifier_put(n);
}
EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister);

struct cec_notifier *
cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name,
          struct cec_adapter *adap)
{
 struct cec_notifier *n;

 if (WARN_ON(!adap))
  return NULL;

 n = cec_notifier_get_conn(hdmi_dev, port_name);
 if (!n)
  return n;

 mutex_lock(&n->lock);
 n->cec_adap = adap;
 adap->conn_info = n->conn_info;
 adap->notifier = n;
 if (!adap->adap_controls_phys_addr)
  cec_s_phys_addr(adap, n->phys_addr, false);
 mutex_unlock(&n->lock);
 return n;
}
EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register);

void cec_notifier_cec_adap_unregister(struct cec_notifier *n,
          struct cec_adapter *adap)
{
 if (!n)
  return;

 mutex_lock(&n->lock);
 adap->notifier = NULL;
 n->cec_adap = NULL;
 mutex_unlock(&n->lock);
 cec_notifier_put(n);
}
EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_unregister);

void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
{
 if (n == NULL)
  return;

 mutex_lock(&n->lock);
 n->phys_addr = pa;
 if (n->cec_adap && !n->cec_adap->adap_controls_phys_addr)
  cec_s_phys_addr(n->cec_adap, n->phys_addr, false);
 mutex_unlock(&n->lock);
}
EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);

/*
 * Note: In the drm subsystem, prefer calling (if possible):
 *
 * cec_notifier_set_phys_addr(n, connector->display_info.source_physical_address);
 */

void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
       const struct edid *edid)
{
 u16 pa = CEC_PHYS_ADDR_INVALID;

 if (n == NULL)
  return;

 if (edid && edid->extensions)
  pa = cec_get_edid_phys_addr((const u8 *)edid,
    EDID_LENGTH * (edid->extensions + 1), NULL);
 cec_notifier_set_phys_addr(n, pa);
}
EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);

struct device *cec_notifier_parse_hdmi_phandle(struct device *dev)
{
 struct platform_device *hdmi_pdev;
 struct device *hdmi_dev = NULL;
 struct device_node *np;

 np = of_parse_phandle(dev->of_node, "hdmi-phandle", 0);

 if (!np) {
  dev_err(dev, "Failed to find HDMI node in device tree\n");
  return ERR_PTR(-ENODEV);
 }

 hdmi_pdev = of_find_device_by_node(np);
 if (hdmi_pdev)
  hdmi_dev = &hdmi_pdev->dev;
#if IS_REACHABLE(CONFIG_I2C)
 if (!hdmi_dev) {
  struct i2c_client *hdmi_client = of_find_i2c_device_by_node(np);

  if (hdmi_client)
   hdmi_dev = &hdmi_client->dev;
 }
#endif
 of_node_put(np);
 if (!hdmi_dev)
  return ERR_PTR(-EPROBE_DEFER);

 /*
 * Note that the device struct is only used as a key into the
 * cec_notifiers list, it is never actually accessed.
 * So we decrement the reference here so we don't leak
 * memory.
 */

 put_device(hdmi_dev);
 return hdmi_dev;
}
EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle);

Messung V0.5
C=99 H=93 G=95

¤ Dauer der Verarbeitung: 0.2 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.