Re: [PATCH 02/10] drm: Add privacy-screen class (v4)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Rajat,

On 11/17/21 15:28, Rajat Jain wrote:
> +Heikki Krogerus
> 
> Hello Hans, Heikki,
> 
> I have a question below, which isn't really a problem, but more of an
> attempt to understand the current code and its limitations.
> 
> On Tue, Oct 5, 2021 at 1:23 PM Hans de Goede <hdegoede@xxxxxxxxxx> wrote:
>>
>> On some new laptops the LCD panel has a builtin electronic privacy-screen.
>> We want to export this functionality as a property on the drm connector
>> object. But often this functionality is not exposed on the GPU but on some
>> other (ACPI) device.
>>
>> This commit adds a privacy-screen class allowing the driver for these
>> other devices to register themselves as a privacy-screen provider; and
>> allowing the drm/kms code to get a privacy-screen provider associated
>> with a specific GPU/connector combo.
>>
>> Changes in v2:
>> - Make CONFIG_DRM_PRIVACY_SCREEN a bool which controls if the drm_privacy
>>   code gets built as part of the main drm module rather then making it
>>   a tristate which builds its own module.
>> - Add a #if IS_ENABLED(CONFIG_DRM_PRIVACY_SCREEN) check to
>>   drm_privacy_screen_consumer.h and define stubs when the check fails.
>>   Together these 2 changes fix several dependency issues.
>> - Remove module related code now that this is part of the main drm.ko
>> - Use drm_class as class for the privacy-screen devices instead of
>>   adding a separate class for this
>>
>> Changes in v3:
>> - Make the static inline drm_privacy_screen_get_state() stub set sw_state
>>   and hw_state to PRIVACY_SCREEN_DISABLED to squelch an uninitialized
>>   variable warning when CONFIG_DRM_PRIVICAY_SCREEN is not set
>>
>> Changes in v4:
>> - Make drm_privacy_screen_set_sw_state() skip calling out to the hw if
>>   hw_state == new_sw_state
>>
>> Reviewed-by: Emil Velikov <emil.l.velikov@xxxxxxxxx>
>> Reviewed-by: Lyude Paul <lyude@xxxxxxxxxx>
>> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
>> ---
>>  Documentation/gpu/drm-kms-helpers.rst     |  15 +
>>  MAINTAINERS                               |   8 +
>>  drivers/gpu/drm/Kconfig                   |   4 +
>>  drivers/gpu/drm/Makefile                  |   1 +
>>  drivers/gpu/drm/drm_drv.c                 |   4 +
>>  drivers/gpu/drm/drm_privacy_screen.c      | 403 ++++++++++++++++++++++
>>  include/drm/drm_privacy_screen_consumer.h |  50 +++
>>  include/drm/drm_privacy_screen_driver.h   |  80 +++++
>>  include/drm/drm_privacy_screen_machine.h  |  41 +++
>>  9 files changed, 606 insertions(+)
>>  create mode 100644 drivers/gpu/drm/drm_privacy_screen.c
>>  create mode 100644 include/drm/drm_privacy_screen_consumer.h
>>  create mode 100644 include/drm/drm_privacy_screen_driver.h
>>  create mode 100644 include/drm/drm_privacy_screen_machine.h
>>
>> diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
>> index ec2f65b31930..5bb55ec1b9b5 100644
>> --- a/Documentation/gpu/drm-kms-helpers.rst
>> +++ b/Documentation/gpu/drm-kms-helpers.rst
>> @@ -435,3 +435,18 @@ Legacy CRTC/Modeset Helper Functions Reference
>>
>>  .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c
>>     :export:
>> +
>> +Privacy-screen class
>> +====================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/drm_privacy_screen.c
>> +   :doc: overview
>> +
>> +.. kernel-doc:: include/drm/drm_privacy_screen_driver.h
>> +   :internal:
>> +
>> +.. kernel-doc:: include/drm/drm_privacy_screen_machine.h
>> +   :internal:
>> +
>> +.. kernel-doc:: drivers/gpu/drm/drm_privacy_screen.c
>> +   :export:
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 28e5f0ae1009..cb94bb3b8724 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6423,6 +6423,14 @@ F:       drivers/gpu/drm/drm_panel.c
>>  F:     drivers/gpu/drm/panel/
>>  F:     include/drm/drm_panel.h
>>
>> +DRM PRIVACY-SCREEN CLASS
>> +M:     Hans de Goede <hdegoede@xxxxxxxxxx>
>> +L:     dri-devel@xxxxxxxxxxxxxxxxxxxxx
>> +S:     Maintained
>> +T:     git git://anongit.freedesktop.org/drm/drm-misc
>> +F:     drivers/gpu/drm/drm_privacy_screen*
>> +F:     include/drm/drm_privacy_screen*
>> +
>>  DRM TTM SUBSYSTEM
>>  M:     Christian Koenig <christian.koenig@xxxxxxx>
>>  M:     Huang Rui <ray.huang@xxxxxxx>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 2a926d0de423..c686c08447ac 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -481,3 +481,7 @@ config DRM_PANEL_ORIENTATION_QUIRKS
>>  config DRM_LIB_RANDOM
>>         bool
>>         default n
>> +
>> +config DRM_PRIVACY_SCREEN
>> +       bool
>> +       default n
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index 0dff40bb863c..788fc37096f6 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -32,6 +32,7 @@ drm-$(CONFIG_OF) += drm_of.o
>>  drm-$(CONFIG_PCI) += drm_pci.o
>>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>> +drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o
>>
>>  obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o
>>
>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> index 7a5097467ba5..dc293b771c3f 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -43,6 +43,7 @@
>>  #include <drm/drm_managed.h>
>>  #include <drm/drm_mode_object.h>
>>  #include <drm/drm_print.h>
>> +#include <drm/drm_privacy_screen_machine.h>
>>
>>  #include "drm_crtc_internal.h"
>>  #include "drm_internal.h"
>> @@ -1029,6 +1030,7 @@ static const struct file_operations drm_stub_fops = {
>>
>>  static void drm_core_exit(void)
>>  {
>> +       drm_privacy_screen_lookup_exit();
>>         unregister_chrdev(DRM_MAJOR, "drm");
>>         debugfs_remove(drm_debugfs_root);
>>         drm_sysfs_destroy();
>> @@ -1056,6 +1058,8 @@ static int __init drm_core_init(void)
>>         if (ret < 0)
>>                 goto error;
>>
>> +       drm_privacy_screen_lookup_init();
>> +
>>         drm_core_init_complete = true;
>>
>>         DRM_DEBUG("Initialized\n");
>> diff --git a/drivers/gpu/drm/drm_privacy_screen.c b/drivers/gpu/drm/drm_privacy_screen.c
>> new file mode 100644
>> index 000000000000..183a6011adf0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_privacy_screen.c
>> @@ -0,0 +1,403 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright (C) 2020 - 2021 Red Hat, Inc.
>> + *
>> + * Authors:
>> + * Hans de Goede <hdegoede@xxxxxxxxxx>
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/list.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <drm/drm_privacy_screen_machine.h>
>> +#include <drm/drm_privacy_screen_consumer.h>
>> +#include <drm/drm_privacy_screen_driver.h>
>> +#include "drm_internal.h"
>> +
>> +/**
>> + * DOC: overview
>> + *
>> + * This class allows non KMS drivers, from e.g. drivers/platform/x86 to
>> + * register a privacy-screen device, which the KMS drivers can then use
>> + * to implement the standard privacy-screen properties, see
>> + * :ref:`Standard Connector Properties<standard_connector_properties>`.
>> + *
>> + * KMS drivers using a privacy-screen class device are advised to use the
>> + * drm_connector_attach_privacy_screen_provider() and
>> + * drm_connector_update_privacy_screen() helpers for dealing with this.
>> + */
>> +
>> +#define to_drm_privacy_screen(dev) \
>> +       container_of(dev, struct drm_privacy_screen, dev)
>> +
>> +static DEFINE_MUTEX(drm_privacy_screen_lookup_lock);
>> +static LIST_HEAD(drm_privacy_screen_lookup_list);
>> +
>> +static DEFINE_MUTEX(drm_privacy_screen_devs_lock);
>> +static LIST_HEAD(drm_privacy_screen_devs);
>> +
>> +/*** drm_privacy_screen_machine.h functions ***/
>> +
>> +/**
>> + * drm_privacy_screen_lookup_add - add an entry to the static privacy-screen
>> + *    lookup list
>> + * @lookup: lookup list entry to add
>> + *
>> + * Add an entry to the static privacy-screen lookup list. Note the
>> + * &struct list_head which is part of the &struct drm_privacy_screen_lookup
>> + * gets added to a list owned by the privacy-screen core. So the passed in
>> + * &struct drm_privacy_screen_lookup must not be free-ed until it is removed
>> + * from the lookup list by calling drm_privacy_screen_lookup_remove().
>> + */
>> +void drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup *lookup)
>> +{
>> +       mutex_lock(&drm_privacy_screen_lookup_lock);
>> +       list_add(&lookup->list, &drm_privacy_screen_lookup_list);
>> +       mutex_unlock(&drm_privacy_screen_lookup_lock);
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_lookup_add);
>> +
>> +/**
>> + * drm_privacy_screen_lookup_remove - remove an entry to the static
>> + *    privacy-screen lookup list
>> + * @lookup: lookup list entry to remove
>> + *
>> + * Remove an entry previously added with drm_privacy_screen_lookup_add()
>> + * from the static privacy-screen lookup list.
>> + */
>> +void drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup *lookup)
>> +{
>> +       mutex_lock(&drm_privacy_screen_lookup_lock);
>> +       list_del(&lookup->list);
>> +       mutex_unlock(&drm_privacy_screen_lookup_lock);
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_lookup_remove);
>> +
>> +/*** drm_privacy_screen_consumer.h functions ***/
>> +
>> +static struct drm_privacy_screen *drm_privacy_screen_get_by_name(
>> +       const char *name)
>> +{
>> +       struct drm_privacy_screen *priv;
>> +       struct device *dev = NULL;
>> +
>> +       mutex_lock(&drm_privacy_screen_devs_lock);
>> +
>> +       list_for_each_entry(priv, &drm_privacy_screen_devs, list) {
>> +               if (strcmp(dev_name(&priv->dev), name) == 0) {
>> +                       dev = get_device(&priv->dev);
>> +                       break;
>> +               }
>> +       }
>> +
>> +       mutex_unlock(&drm_privacy_screen_devs_lock);
>> +
>> +       return dev ? to_drm_privacy_screen(dev) : NULL;
>> +}
>> +
>> +/**
>> + * drm_privacy_screen_get - get a privacy-screen provider
>> + * @dev: consumer-device for which to get a privacy-screen provider
>> + * @con_id: (video)connector name for which to get a privacy-screen provider
>> + *
>> + * Get a privacy-screen provider for a privacy-screen attached to the
>> + * display described by the @dev and @con_id parameters.
>> + *
>> + * Return:
>> + * * A pointer to a &struct drm_privacy_screen on success.
>> + * * ERR_PTR(-ENODEV) if no matching privacy-screen is found
>> + * * ERR_PTR(-EPROBE_DEFER) if there is a matching privacy-screen,
>> + *                          but it has not been registered yet.
>> + */
>> +struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
>> +                                                 const char *con_id)
>> +{
>> +       const char *dev_id = dev ? dev_name(dev) : NULL;
>> +       struct drm_privacy_screen_lookup *l;
>> +       struct drm_privacy_screen *priv;
>> +       const char *provider = NULL;
>> +       int match, best = -1;
>> +
>> +       /*
>> +        * For now we only support using a static lookup table, which is
>> +        * populated by the drm_privacy_screen_arch_init() call. This should()
>> +        * be extended with device-tree / fw_node lookup when support is added
>> +        * for device-tree using hardware with a privacy-screen.
> 
> Do I understand it right that given the state of affairs today, the
> drm_connector->fwnode gets populated AFTER the drm_connectors are
> initialized and the connector properties have already been attached?
> [intel_acpi_assign_connector_fwnodes() gets called later]. If so, the
> fwnode, can't really be used to tweak certain properties of the
> drm-connector?
> 
> Specifically, if someone wants to use device-tree / fwnodes for
> drm_connector to provide a privacy-screen property, we have a
> chicken-and-egg situation because:
>  - privacy-screen providers need to register privacy-screen, BEFORE
> drm_connector begins to probe and attach properties.
>  - the drm_connector->fwnode gets assigned AFTER drm_connector has
> attached the properties.
> 
> Is the above a correct understanding of the current situation?

the drm_connector->fwnode pointer is atm only used for 
drm_connector_find_by_fwnode() which in turn is only used together
with drm_connector_oob_hotplug_event() for some Type-c setups.

For privacy-screens stuff the idea would be that at some points
the i915 code calls:

	privacy_screen = drm_privacy_screen_get(dev->dev, con_id);

And then drm_privacy_screen_get() would check for "connector"
child fwnode-s under dev->dev.fwnode and search for the one which
has a name / con_id property matching the passed in con_id and
then it has found the fwnode for the connector without needing
to use the drm_connector->fwnode link.

So I believe that for a devicetree privacy_screen implementation
the whole drm_connector->fwnode link is not needed.

Regards,

Hans


p.s.

It would probably still be nice to also set drm_connector->fwnode
on devicetree based platforms so that drm_connector_find_by_fwnode()
works and can be used on those platforms if we need it there.



>> +        *
>> +        * The lookup algorithm was shamelessly taken from the clock
>> +        * framework:
>> +        *
>> +        * We do slightly fuzzy matching here:
>> +        *  An entry with a NULL ID is assumed to be a wildcard.
>> +        *  If an entry has a device ID, it must match
>> +        *  If an entry has a connection ID, it must match
>> +        * Then we take the most specific entry - with the following order
>> +        * of precedence: dev+con > dev only > con only.
>> +        */
>> +       mutex_lock(&drm_privacy_screen_lookup_lock);
>> +
>> +       list_for_each_entry(l, &drm_privacy_screen_lookup_list, list) {
>> +               match = 0;
>> +
>> +               if (l->dev_id) {
>> +                       if (!dev_id || strcmp(l->dev_id, dev_id))
>> +                               continue;
>> +
>> +                       match += 2;
>> +               }
>> +
>> +               if (l->con_id) {
>> +                       if (!con_id || strcmp(l->con_id, con_id))
>> +                               continue;
>> +
>> +                       match += 1;
>> +               }
>> +
>> +               if (match > best) {
>> +                       provider = l->provider;
>> +                       best = match;
>> +               }
>> +       }
>> +
>> +       mutex_unlock(&drm_privacy_screen_lookup_lock);
>> +
>> +       if (!provider)
>> +               return ERR_PTR(-ENODEV);
>> +
>> +       priv = drm_privacy_screen_get_by_name(provider);
>> +       if (!priv)
>> +               return ERR_PTR(-EPROBE_DEFER);
>> +
>> +       return priv;
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_get);
>> +
>> +/**
>> + * drm_privacy_screen_put - release a privacy-screen reference
>> + * @priv: privacy screen reference to release
>> + *
>> + * Release a privacy-screen provider reference gotten through
>> + * drm_privacy_screen_get(). May be called with a NULL or ERR_PTR,
>> + * in which case it is a no-op.
>> + */
>> +void drm_privacy_screen_put(struct drm_privacy_screen *priv)
>> +{
>> +       if (IS_ERR_OR_NULL(priv))
>> +               return;
>> +
>> +       put_device(&priv->dev);
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_put);
>> +
>> +/**
>> + * drm_privacy_screen_set_sw_state - set a privacy-screen's sw-state
>> + * @priv: privacy screen to set the sw-state for
>> + * @sw_state: new sw-state value to set
>> + *
>> + * Set the sw-state of a privacy screen. If the privacy-screen is not
>> + * in a locked hw-state, then the actual and hw-state of the privacy-screen
>> + * will be immediately updated to the new value. If the privacy-screen is
>> + * in a locked hw-state, then the new sw-state will be remembered as the
>> + * requested state to put the privacy-screen in when it becomes unlocked.
>> + *
>> + * Return: 0 on success, negative error code on failure.
>> + */
>> +int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
>> +                                   enum drm_privacy_screen_status sw_state)
>> +{
>> +       int ret = 0;
>> +
>> +       mutex_lock(&priv->lock);
>> +
>> +       if (!priv->ops) {
>> +               ret = -ENODEV;
>> +               goto out;
>> +       }
>> +
>> +       /*
>> +        * As per the DRM connector properties documentation, setting the
>> +        * sw_state while the hw_state is locked is allowed. In this case
>> +        * it is a no-op other then storing the new sw_state so that it
>> +        * can be honored when the state gets unlocked.
>> +        * Also skip the set if the hw already is in the desired state.
>> +        */
>> +       if (priv->hw_state >= PRIVACY_SCREEN_DISABLED_LOCKED ||
>> +           priv->hw_state == sw_state) {
>> +               priv->sw_state = sw_state;
>> +               goto out;
>> +       }
>> +
>> +       ret = priv->ops->set_sw_state(priv, sw_state);
>> +out:
>> +       mutex_unlock(&priv->lock);
>> +       return ret;
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_set_sw_state);
>> +
>> +/**
>> + * drm_privacy_screen_get_state - get privacy-screen's current state
>> + * @priv: privacy screen to get the state for
>> + * @sw_state_ret: address where to store the privacy-screens current sw-state
>> + * @hw_state_ret: address where to store the privacy-screens current hw-state
>> + *
>> + * Get the current state of a privacy-screen, both the sw-state and the
>> + * hw-state.
>> + */
>> +void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
>> +                                 enum drm_privacy_screen_status *sw_state_ret,
>> +                                 enum drm_privacy_screen_status *hw_state_ret)
>> +{
>> +       mutex_lock(&priv->lock);
>> +       *sw_state_ret = priv->sw_state;
>> +       *hw_state_ret = priv->hw_state;
>> +       mutex_unlock(&priv->lock);
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_get_state);
>> +
>> +/*** drm_privacy_screen_driver.h functions ***/
>> +
>> +static ssize_t sw_state_show(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
>> +       const char * const sw_state_names[] = {
>> +               "Disabled",
>> +               "Enabled",
>> +       };
>> +       ssize_t ret;
>> +
>> +       mutex_lock(&priv->lock);
>> +
>> +       if (!priv->ops)
>> +               ret = -ENODEV;
>> +       else if (WARN_ON(priv->sw_state >= ARRAY_SIZE(sw_state_names)))
>> +               ret = -ENXIO;
>> +       else
>> +               ret = sprintf(buf, "%s\n", sw_state_names[priv->sw_state]);
>> +
>> +       mutex_unlock(&priv->lock);
>> +       return ret;
>> +}
>> +/*
>> + * RO: Do not allow setting the sw_state through sysfs, this MUST be done
>> + * through the drm_properties on the drm_connector.
>> + */
>> +static DEVICE_ATTR_RO(sw_state);
>> +
>> +static ssize_t hw_state_show(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
>> +       const char * const hw_state_names[] = {
>> +               "Disabled",
>> +               "Enabled",
>> +               "Disabled, locked",
>> +               "Enabled, locked",
>> +       };
>> +       ssize_t ret;
>> +
>> +       mutex_lock(&priv->lock);
>> +
>> +       if (!priv->ops)
>> +               ret = -ENODEV;
>> +       else if (WARN_ON(priv->hw_state >= ARRAY_SIZE(hw_state_names)))
>> +               ret = -ENXIO;
>> +       else
>> +               ret = sprintf(buf, "%s\n", hw_state_names[priv->hw_state]);
>> +
>> +       mutex_unlock(&priv->lock);
>> +       return ret;
>> +}
>> +static DEVICE_ATTR_RO(hw_state);
>> +
>> +static struct attribute *drm_privacy_screen_attrs[] = {
>> +       &dev_attr_sw_state.attr,
>> +       &dev_attr_hw_state.attr,
>> +       NULL
>> +};
>> +ATTRIBUTE_GROUPS(drm_privacy_screen);
>> +
>> +static struct device_type drm_privacy_screen_type = {
>> +       .name = "privacy_screen",
>> +       .groups = drm_privacy_screen_groups,
>> +};
>> +
>> +static void drm_privacy_screen_device_release(struct device *dev)
>> +{
>> +       struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
>> +
>> +       kfree(priv);
>> +}
>> +
>> +/**
>> + * drm_privacy_screen_register - register a privacy-screen
>> + * @parent: parent-device for the privacy-screen
>> + * @ops: &struct drm_privacy_screen_ops pointer with ops for the privacy-screen
>> + *
>> + * Create and register a privacy-screen.
>> + *
>> + * Return:
>> + * * A pointer to the created privacy-screen on success.
>> + * * An ERR_PTR(errno) on failure.
>> + */
>> +struct drm_privacy_screen *drm_privacy_screen_register(
>> +       struct device *parent, const struct drm_privacy_screen_ops *ops)
>> +{
>> +       struct drm_privacy_screen *priv;
>> +       int ret;
>> +
>> +       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>> +       if (!priv)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       mutex_init(&priv->lock);
>> +
>> +       priv->dev.class = drm_class;
>> +       priv->dev.type = &drm_privacy_screen_type;
>> +       priv->dev.parent = parent;
>> +       priv->dev.release = drm_privacy_screen_device_release;
>> +       dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent));
>> +       priv->ops = ops;
>> +
>> +       priv->ops->get_hw_state(priv);
>> +
>> +       ret = device_register(&priv->dev);
>> +       if (ret) {
>> +               put_device(&priv->dev);
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       mutex_lock(&drm_privacy_screen_devs_lock);
>> +       list_add(&priv->list, &drm_privacy_screen_devs);
>> +       mutex_unlock(&drm_privacy_screen_devs_lock);
>> +
>> +       return priv;
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_register);
>> +
>> +/**
>> + * drm_privacy_screen_unregister - unregister privacy-screen
>> + * @priv: privacy-screen to unregister
>> + *
>> + * Unregister a privacy-screen registered with drm_privacy_screen_register().
>> + * May be called with a NULL or ERR_PTR, in which case it is a no-op.
>> + */
>> +void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
>> +{
>> +       if (IS_ERR_OR_NULL(priv))
>> +               return;
>> +
>> +       mutex_lock(&drm_privacy_screen_devs_lock);
>> +       list_del(&priv->list);
>> +       mutex_unlock(&drm_privacy_screen_devs_lock);
>> +
>> +       mutex_lock(&priv->lock);
>> +       priv->ops = NULL;
>> +       mutex_unlock(&priv->lock);
>> +
>> +       device_unregister(&priv->dev);
>> +}
>> +EXPORT_SYMBOL(drm_privacy_screen_unregister);
>> diff --git a/include/drm/drm_privacy_screen_consumer.h b/include/drm/drm_privacy_screen_consumer.h
>> new file mode 100644
>> index 000000000000..0cbd23b0453d
>> --- /dev/null
>> +++ b/include/drm/drm_privacy_screen_consumer.h
>> @@ -0,0 +1,50 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright (C) 2020 Red Hat, Inc.
>> + *
>> + * Authors:
>> + * Hans de Goede <hdegoede@xxxxxxxxxx>
>> + */
>> +
>> +#ifndef __DRM_PRIVACY_SCREEN_CONSUMER_H__
>> +#define __DRM_PRIVACY_SCREEN_CONSUMER_H__
>> +
>> +#include <linux/device.h>
>> +#include <drm/drm_connector.h>
>> +
>> +struct drm_privacy_screen;
>> +
>> +#if IS_ENABLED(CONFIG_DRM_PRIVACY_SCREEN)
>> +struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
>> +                                                 const char *con_id);
>> +void drm_privacy_screen_put(struct drm_privacy_screen *priv);
>> +
>> +int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
>> +                                   enum drm_privacy_screen_status sw_state);
>> +void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
>> +                                 enum drm_privacy_screen_status *sw_state_ret,
>> +                                 enum drm_privacy_screen_status *hw_state_ret);
>> +#else
>> +static inline struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
>> +                                                               const char *con_id)
>> +{
>> +       return ERR_PTR(-ENODEV);
>> +}
>> +static inline void drm_privacy_screen_put(struct drm_privacy_screen *priv)
>> +{
>> +}
>> +static inline int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
>> +                                                 enum drm_privacy_screen_status sw_state)
>> +{
>> +       return -ENODEV;
>> +}
>> +static inline void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
>> +                                               enum drm_privacy_screen_status *sw_state_ret,
>> +                                               enum drm_privacy_screen_status *hw_state_ret)
>> +{
>> +       *sw_state_ret = PRIVACY_SCREEN_DISABLED;
>> +       *hw_state_ret = PRIVACY_SCREEN_DISABLED;
>> +}
>> +#endif
>> +
>> +#endif
>> diff --git a/include/drm/drm_privacy_screen_driver.h b/include/drm/drm_privacy_screen_driver.h
>> new file mode 100644
>> index 000000000000..5187ae52eb03
>> --- /dev/null
>> +++ b/include/drm/drm_privacy_screen_driver.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright (C) 2020 Red Hat, Inc.
>> + *
>> + * Authors:
>> + * Hans de Goede <hdegoede@xxxxxxxxxx>
>> + */
>> +
>> +#ifndef __DRM_PRIVACY_SCREEN_DRIVER_H__
>> +#define __DRM_PRIVACY_SCREEN_DRIVER_H__
>> +
>> +#include <linux/device.h>
>> +#include <linux/list.h>
>> +#include <linux/mutex.h>
>> +#include <drm/drm_connector.h>
>> +
>> +struct drm_privacy_screen;
>> +
>> +/**
>> + * struct drm_privacy_screen_ops - drm_privacy_screen operations
>> + *
>> + * Defines the operations which the privacy-screen class code may call.
>> + * These functions should be implemented by the privacy-screen driver.
>> + */
>> +struct drm_privacy_screen_ops {
>> +       /**
>> +        * @set_sw_state: Called to request a change of the privacy-screen
>> +        * state. The privacy-screen class code contains a check to avoid this
>> +        * getting called when the hw_state reports the state is locked.
>> +        * It is the driver's responsibility to update sw_state and hw_state.
>> +        * This is always called with the drm_privacy_screen's lock held.
>> +        */
>> +       int (*set_sw_state)(struct drm_privacy_screen *priv,
>> +                           enum drm_privacy_screen_status sw_state);
>> +       /**
>> +        * @get_hw_state: Called to request that the driver gets the current
>> +        * privacy-screen state from the hardware and then updates sw_state and
>> +        * hw_state accordingly. This will be called by the core just before
>> +        * the privacy-screen is registered in sysfs.
>> +        */
>> +       void (*get_hw_state)(struct drm_privacy_screen *priv);
>> +};
>> +
>> +/**
>> + * struct drm_privacy_screen - central privacy-screen structure
>> + *
>> + * Central privacy-screen structure, this contains the struct device used
>> + * to register the screen in sysfs, the screen's state, ops, etc.
>> + */
>> +struct drm_privacy_screen {
>> +       /** @dev: device used to register the privacy-screen in sysfs. */
>> +       struct device dev;
>> +       /** @lock: mutex protection all fields in this struct. */
>> +       struct mutex lock;
>> +       /** @list: privacy-screen devices list list-entry. */
>> +       struct list_head list;
>> +       /**
>> +        * @ops: &struct drm_privacy_screen_ops for this privacy-screen.
>> +        * This is NULL if the driver has unregistered the privacy-screen.
>> +        */
>> +       const struct drm_privacy_screen_ops *ops;
>> +       /**
>> +        * @sw_state: The privacy-screen's software state, see
>> +        * :ref:`Standard Connector Properties<standard_connector_properties>`
>> +        * for more info.
>> +        */
>> +       enum drm_privacy_screen_status sw_state;
>> +       /**
>> +        * @hw_state: The privacy-screen's hardware state, see
>> +        * :ref:`Standard Connector Properties<standard_connector_properties>`
>> +        * for more info.
>> +        */
>> +       enum drm_privacy_screen_status hw_state;
>> +};
>> +
>> +struct drm_privacy_screen *drm_privacy_screen_register(
>> +       struct device *parent, const struct drm_privacy_screen_ops *ops);
>> +void drm_privacy_screen_unregister(struct drm_privacy_screen *priv);
>> +
>> +#endif
>> diff --git a/include/drm/drm_privacy_screen_machine.h b/include/drm/drm_privacy_screen_machine.h
>> new file mode 100644
>> index 000000000000..aaa0d38cce92
>> --- /dev/null
>> +++ b/include/drm/drm_privacy_screen_machine.h
>> @@ -0,0 +1,41 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright (C) 2020 Red Hat, Inc.
>> + *
>> + * Authors:
>> + * Hans de Goede <hdegoede@xxxxxxxxxx>
>> + */
>> +
>> +#ifndef __DRM_PRIVACY_SCREEN_MACHINE_H__
>> +#define __DRM_PRIVACY_SCREEN_MACHINE_H__
>> +
>> +#include <linux/list.h>
>> +
>> +/**
>> + * struct drm_privacy_screen_lookup -  static privacy-screen lookup list entry
>> + *
>> + * Used for the static lookup-list for mapping privacy-screen consumer
>> + * dev-connector pairs to a privacy-screen provider.
>> + */
>> +struct drm_privacy_screen_lookup {
>> +       /** @list: Lookup list list-entry. */
>> +       struct list_head list;
>> +       /** @dev_id: Consumer device name or NULL to match all devices. */
>> +       const char *dev_id;
>> +       /** @con_id: Consumer connector name or NULL to match all connectors. */
>> +       const char *con_id;
>> +       /** @provider: dev_name() of the privacy_screen provider. */
>> +       const char *provider;
>> +};
>> +
>> +void drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup *lookup);
>> +void drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup *lookup);
>> +
>> +static inline void drm_privacy_screen_lookup_init(void)
>> +{
>> +}
>> +static inline void drm_privacy_screen_lookup_exit(void)
>> +{
>> +}
>> +
>> +#endif
>> --
>> 2.31.1
>>
> 




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux