Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp3707445ybi; Sun, 2 Jun 2019 21:36:18 -0700 (PDT) X-Google-Smtp-Source: APXvYqzGLaWtGr9ygmifIhl4Bo4time4E/wNa0DvW+xzTiILZXzO7WUu5tSL3wOsGH0MjMHAVH6Y X-Received: by 2002:aa7:93ba:: with SMTP id x26mr28149667pff.238.1559536578362; Sun, 02 Jun 2019 21:36:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559536578; cv=none; d=google.com; s=arc-20160816; b=JquQczXOqLEs1S2S99MnIATLcmGZqTBb6RMwlXI0Qu7YleiSUL/2kYkzFHyxyUIR+7 FWvil0pTjzXrnC4j+awXzkRFzF2Hj9Dmm/OpLHUXj4wAsW7eTPBOfI+kl67NNNpyMs65 oPiOmCjIoasXY5wyMBTTBWzSCa7614tC/8PjFCjXq3bjlWqwMgdT/n8nu3g0XmNdvB// K96Iz00/t8ekwignygP+dqJ5blrdfPgrlPT21vbbVYlKnd+lsSVR+ax1x0/iW2ziO7R4 r/78M0EjvE66DTrIstZeVB0/peRusQbQO1ZWlYWGjJV//AN9/l7JZ2azOpJj1HqpPaTQ hETQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=2Kwlb/5SiHsOyNhbzKStBJCJEYsXKEdQeHEGccB6G4g=; b=n4QzIxwkTzyO6fVuawmHN2+ecvTaYI0AFw+JenwmxdQl65SqTa6rCV3A22C2nqT4zw CXkM5FYwf9PJMPqcwfnOwGjoXk51GANCIsCFvYO3h/G2iIK3FKhOfmqHv7BSptgJY0ub LFZcjqT3R0XrIMC4lXUsXepltr8lLTbOT8VtoZbYks6EwADCem/Xm0NZq326aJYw8f66 FdQEvAJ1S2YwUuBbsgboOjEmSf08x4lQq/uoWTmhVdOtd8L1ejaxyevhM77Jskb7lEGj GRjsShf9fy+IfIeLYpHfgIDt3e2fGTblaIXWi01zAlWiJDyGkMVy/zAyZtKHhKncu9st FbCg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=P6sxjq2j; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u22si320384pgj.550.2019.06.02.21.36.02; Sun, 02 Jun 2019 21:36:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=P6sxjq2j; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726820AbfFCEd3 (ORCPT + 99 others); Mon, 3 Jun 2019 00:33:29 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:38081 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726774AbfFCEd2 (ORCPT ); Mon, 3 Jun 2019 00:33:28 -0400 Received: by mail-pf1-f194.google.com with SMTP id a186so9120826pfa.5 for ; Sun, 02 Jun 2019 21:33:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2Kwlb/5SiHsOyNhbzKStBJCJEYsXKEdQeHEGccB6G4g=; b=P6sxjq2jhBsuLFH1QG7yv4BIJAceIkzfv21qakj+ocuLcqfruJgk8Nknotu7hXPdaC EQcrUw8uZQZtGwzDPMO+UKmcFiYcFtWe24y7eP0FnYNYU9Oeb7vNiFUhp8MUd4YT8VaQ MaqS3sJXoC3FphFKT1F25QPEx3fflQgHYxwRo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2Kwlb/5SiHsOyNhbzKStBJCJEYsXKEdQeHEGccB6G4g=; b=fAI5qZS5+H2DIpmYDvJEt5ugmD4jwwKluJTDJLaoWBFIV9iXTvPTa/j+Udb0lblip/ tJVjg/vymEuDFldYJeURVO9gUjWFNiP6oOZ7vCIoPWbm3OFOI0a4CnOoIN/OaLN66E60 V4LjT6zMKoW5QnQSQltliCapSP4Avk+h9pQ4P8c6hvoy0lMRnt95Lsdwiss9JE1yB/fB zRjNl9+vKkw6qNUDUDO3UBO3gMn0+SQcvot4HudcefAGhxSK53ssrP7fHa4d5INVpPvX 0yYk8gGNncHF65+tCMTCO6cVRFZgvlofoU2P9aWhPuoEmzAzZpZQOQHYCVu+Yzr0CTZU pHaA== X-Gm-Message-State: APjAAAXuscQxaihVf8eC1PjOEG7LvDadH6eptFa8SO3L+3KVkZkluWWc MuCAKDhZWLpHEZy7sLsUAMdT2J4UvVk= X-Received: by 2002:a63:18e:: with SMTP id 136mr25981553pgb.277.1559536407123; Sun, 02 Jun 2019 21:33:27 -0700 (PDT) Received: from localhost ([2401:fa00:1:b:e688:dfd2:a1a7:2956]) by smtp.gmail.com with ESMTPSA id h12sm2623108pfr.38.2019.06.02.21.33.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 02 Jun 2019 21:33:26 -0700 (PDT) From: Cheng-Yi Chiang To: linux-kernel@vger.kernel.org Cc: Hans Verkuil , Bartlomiej Zolnierkiewicz , Greg Kroah-Hartman , Philipp Zabel , Mark Brown , Liam Girdwood , Takashi Iwai , Jaroslav Kysela , Russell King , Andrzej Hajda , Laurent Pinchart , David Airlie , Daniel Vetter , Rob Herring , Heiko Stuebner , dianders@chromium.org, dgreid@chromium.org, tzungbi@chromium.org, linux-media@vger.kernel.org, alsa-devel@alsa-project.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org, Hans Verkuil , Cheng-Yi Chiang Subject: [PATCH 1/7] video: add HDMI state notifier support Date: Mon, 3 Jun 2019 12:32:45 +0800 Message-Id: <20190603043251.226549-2-cychiang@chromium.org> X-Mailer: git-send-email 2.22.0.rc1.257.g3120a18244-goog In-Reply-To: <20190603043251.226549-1-cychiang@chromium.org> References: <20190603043251.226549-1-cychiang@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Hans Verkuil Add support for HDMI hotplug and EDID notifiers, which is used to convey information from HDMI drivers to their CEC and audio counterparts. Based on an earlier version from Russell King: https://patchwork.kernel.org/patch/9277043/ The hdmi_notifier is a reference counted object containing the HDMI state of an HDMI device. When a new notifier is registered the current state will be reported to that notifier at registration time. Based on Hans Verkuil's patch: https://patchwork.kernel.org/patch/9472521/ Modified by Cheng-Yi Chiang: - Add a section in MAINTAINER. - Changes connected and has_eld to bitfield of unsigned int. - Other minor fixes to pass checkpatch.pl --strict checks. Signed-off-by: Hans Verkuil Acked-by: Philipp Zabel Signed-off-by: Cheng-Yi Chiang --- The original patch is at https://lore.kernel.org/linux-arm-kernel/20161213150813.37966-2-hverkuil@xs4all.nl MAINTAINERS | 6 ++ drivers/video/Kconfig | 3 + drivers/video/Makefile | 1 + drivers/video/hdmi-notifier.c | 145 ++++++++++++++++++++++++++++++++++ include/linux/hdmi-notifier.h | 112 ++++++++++++++++++++++++++ 5 files changed, 267 insertions(+) create mode 100644 drivers/video/hdmi-notifier.c create mode 100644 include/linux/hdmi-notifier.h diff --git a/MAINTAINERS b/MAINTAINERS index 5cfbea4ce575..ffb7376f9509 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16676,6 +16676,12 @@ W: https://linuxtv.org S: Maintained F: drivers/media/platform/vicodec/* +VIDEO FRAMEWORK +M: Hans Verkuil +L: linux-media@vger.kernel.org +F: drivers/video/hdmi-notifier.* +S: Maintained + VIDEO MULTIPLEXER DRIVER M: Philipp Zabel L: linux-media@vger.kernel.org diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 83d3d271ca15..000ba9bc0ae7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -34,6 +34,9 @@ config VIDEOMODE_HELPERS config HDMI bool +config HDMI_NOTIFIERS + bool + endif # HAS_IOMEM if VT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index df7650adede9..eff4736102ca 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VGASTATE) += vgastate.o obj-$(CONFIG_HDMI) += hdmi.o +obj-$(CONFIG_HDMI_NOTIFIERS) += hdmi-notifier.o obj-$(CONFIG_VT) += console/ obj-$(CONFIG_FB_STI) += console/ diff --git a/drivers/video/hdmi-notifier.c b/drivers/video/hdmi-notifier.c new file mode 100644 index 000000000000..d1eedf661648 --- /dev/null +++ b/drivers/video/hdmi-notifier.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* hdmi-notifier.c - notify interested parties of (dis)connect and EDID + * events + * + * Copyright 2016 Russell King + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + */ + +#include +#include +#include +#include +#include + +static LIST_HEAD(hdmi_notifiers); +static DEFINE_MUTEX(hdmi_notifiers_lock); + +struct hdmi_notifier *hdmi_notifier_get(struct device *dev) +{ + struct hdmi_notifier *n; + + mutex_lock(&hdmi_notifiers_lock); + list_for_each_entry(n, &hdmi_notifiers, head) { + if (n->dev == dev) { + mutex_unlock(&hdmi_notifiers_lock); + kref_get(&n->kref); + return n; + } + } + n = kzalloc(sizeof(*n), GFP_KERNEL); + if (!n) + goto unlock; + n->dev = dev; + mutex_init(&n->lock); + BLOCKING_INIT_NOTIFIER_HEAD(&n->notifiers); + kref_init(&n->kref); + list_add_tail(&n->head, &hdmi_notifiers); +unlock: + mutex_unlock(&hdmi_notifiers_lock); + return n; +} +EXPORT_SYMBOL_GPL(hdmi_notifier_get); + +static void hdmi_notifier_release(struct kref *kref) +{ + struct hdmi_notifier *n = + container_of(kref, struct hdmi_notifier, kref); + + mutex_lock(&hdmi_notifiers_lock); + list_del(&n->head); + mutex_unlock(&hdmi_notifiers_lock); + kfree(n->edid); + kfree(n); +} + +void hdmi_notifier_put(struct hdmi_notifier *n) +{ + kref_put(&n->kref, hdmi_notifier_release); +} +EXPORT_SYMBOL_GPL(hdmi_notifier_put); + +int hdmi_notifier_register(struct hdmi_notifier *n, struct notifier_block *nb) +{ + int ret = blocking_notifier_chain_register(&n->notifiers, nb); + + if (ret) + return ret; + kref_get(&n->kref); + mutex_lock(&n->lock); + if (n->connected) { + blocking_notifier_call_chain(&n->notifiers, HDMI_CONNECTED, n); + if (n->edid_size) + blocking_notifier_call_chain(&n->notifiers, + HDMI_NEW_EDID, n); + if (n->has_eld) + blocking_notifier_call_chain(&n->notifiers, + HDMI_NEW_ELD, n); + } + mutex_unlock(&n->lock); + return 0; +} +EXPORT_SYMBOL_GPL(hdmi_notifier_register); + +int hdmi_notifier_unregister(struct hdmi_notifier *n, struct notifier_block *nb) +{ + int ret = blocking_notifier_chain_unregister(&n->notifiers, nb); + + if (ret == 0) + hdmi_notifier_put(n); + return ret; +} +EXPORT_SYMBOL_GPL(hdmi_notifier_unregister); + +void hdmi_event_connect(struct hdmi_notifier *n) +{ + mutex_lock(&n->lock); + n->connected = true; + blocking_notifier_call_chain(&n->notifiers, HDMI_CONNECTED, n); + mutex_unlock(&n->lock); +} +EXPORT_SYMBOL_GPL(hdmi_event_connect); + +void hdmi_event_disconnect(struct hdmi_notifier *n) +{ + mutex_lock(&n->lock); + n->connected = false; + n->has_eld = false; + n->edid_size = 0; + blocking_notifier_call_chain(&n->notifiers, HDMI_DISCONNECTED, n); + mutex_unlock(&n->lock); +} +EXPORT_SYMBOL_GPL(hdmi_event_disconnect); + +int hdmi_event_new_edid(struct hdmi_notifier *n, const void *edid, size_t size) +{ + mutex_lock(&n->lock); + if (n->edid_allocated_size < size) { + void *p = kmalloc(size, GFP_KERNEL); + + if (!p) { + mutex_unlock(&n->lock); + return -ENOMEM; + } + kfree(n->edid); + n->edid = p; + n->edid_allocated_size = size; + } + memcpy(n->edid, edid, size); + n->edid_size = size; + blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_EDID, n); + mutex_unlock(&n->lock); + return 0; +} +EXPORT_SYMBOL_GPL(hdmi_event_new_edid); + +void hdmi_event_new_eld(struct hdmi_notifier *n, const u8 eld[128]) +{ + mutex_lock(&n->lock); + memcpy(n->eld, eld, sizeof(n->eld)); + n->has_eld = true; + blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_ELD, n); + mutex_unlock(&n->lock); +} +EXPORT_SYMBOL_GPL(hdmi_event_new_eld); diff --git a/include/linux/hdmi-notifier.h b/include/linux/hdmi-notifier.h new file mode 100644 index 000000000000..c8f35110e3e3 --- /dev/null +++ b/include/linux/hdmi-notifier.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 + * hdmi-notifier.h - notify interested parties of (dis)connect and EDID + * events + * + * Copyright 2016 Russell King + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + */ + +#ifndef LINUX_HDMI_NOTIFIER_H +#define LINUX_HDMI_NOTIFIER_H + +#include +#include +#include + +enum { + HDMI_CONNECTED, + HDMI_DISCONNECTED, + HDMI_NEW_EDID, + HDMI_NEW_ELD, +}; + +struct device; + +struct hdmi_notifier { + /* Lock to protect callback registration and notification. */ + struct mutex lock; + struct list_head head; + struct kref kref; + struct blocking_notifier_head notifiers; + struct device *dev; + + /* Current state */ + unsigned int connected : 1; + unsigned int has_eld : 1; + unsigned char eld[128]; + void *edid; + size_t edid_size; + size_t edid_allocated_size; +}; + +/** + * hdmi_notifier_get - find or create a new hdmi_notifier for the given device. + * @dev: device that sends the events. + * + * 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. + */ +struct hdmi_notifier *hdmi_notifier_get(struct device *dev); + +/** + * hdmi_notifier_put - decrease refcount and delete when the refcount reaches 0. + * @n: notifier + */ +void hdmi_notifier_put(struct hdmi_notifier *n); + +/** + * hdmi_notifier_register - register the notifier with the notifier_block. + * @n: the HDMI notifier + * @nb: the notifier_block + */ +int hdmi_notifier_register(struct hdmi_notifier *n, struct notifier_block *nb); + +/** + * hdmi_notifier_unregister - unregister the notifier with the notifier_block. + * @n: the HDMI notifier + * @nb: the notifier_block + */ +int hdmi_notifier_unregister(struct hdmi_notifier *n, + struct notifier_block *nb); + +/** + * hdmi_event_connect - send a connect event. + * @n: the HDMI notifier + * + * Send an HDMI_CONNECTED event to any registered parties. + */ +void hdmi_event_connect(struct hdmi_notifier *n); + +/** + * hdmi_event_disconnect - send a disconnect event. + * @n: the HDMI notifier + * + * Send an HDMI_DISCONNECTED event to any registered parties. + */ +void hdmi_event_disconnect(struct hdmi_notifier *n); + +/** + * hdmi_event_new_edid - send a new EDID event. + * @n: the HDMI notifier + * + * Send an HDMI_NEW_EDID event to any registered parties. + * This function will make a copy the EDID so it can return -ENOMEM if + * no memory could be allocated. + */ +int hdmi_event_new_edid(struct hdmi_notifier *n, const void *edid, size_t size); + +/** + * hdmi_event_new_eld - send a new ELD event. + * @n: the HDMI notifier + * + * Send an HDMI_NEW_ELD event to any registered parties. + */ +void hdmi_event_new_eld(struct hdmi_notifier *n, const u8 eld[128]); + +#endif -- 2.22.0.rc1.257.g3120a18244-goog