Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright (C) 2020 - 2021 Red Hat, Inc.
0004  *
0005  * Authors:
0006  * Hans de Goede <hdegoede@redhat.com>
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/kernel.h>
0011 #include <linux/list.h>
0012 #include <linux/module.h>
0013 #include <linux/mutex.h>
0014 #include <linux/slab.h>
0015 #include <drm/drm_privacy_screen_machine.h>
0016 #include <drm/drm_privacy_screen_consumer.h>
0017 #include <drm/drm_privacy_screen_driver.h>
0018 #include "drm_internal.h"
0019 
0020 /**
0021  * DOC: overview
0022  *
0023  * This class allows non KMS drivers, from e.g. drivers/platform/x86 to
0024  * register a privacy-screen device, which the KMS drivers can then use
0025  * to implement the standard privacy-screen properties, see
0026  * :ref:`Standard Connector Properties<standard_connector_properties>`.
0027  *
0028  * KMS drivers using a privacy-screen class device are advised to use the
0029  * drm_connector_attach_privacy_screen_provider() and
0030  * drm_connector_update_privacy_screen() helpers for dealing with this.
0031  */
0032 
0033 #define to_drm_privacy_screen(dev) \
0034     container_of(dev, struct drm_privacy_screen, dev)
0035 
0036 static DEFINE_MUTEX(drm_privacy_screen_lookup_lock);
0037 static LIST_HEAD(drm_privacy_screen_lookup_list);
0038 
0039 static DEFINE_MUTEX(drm_privacy_screen_devs_lock);
0040 static LIST_HEAD(drm_privacy_screen_devs);
0041 
0042 /*** drm_privacy_screen_machine.h functions ***/
0043 
0044 /**
0045  * drm_privacy_screen_lookup_add - add an entry to the static privacy-screen
0046  *    lookup list
0047  * @lookup: lookup list entry to add
0048  *
0049  * Add an entry to the static privacy-screen lookup list. Note the
0050  * &struct list_head which is part of the &struct drm_privacy_screen_lookup
0051  * gets added to a list owned by the privacy-screen core. So the passed in
0052  * &struct drm_privacy_screen_lookup must not be free-ed until it is removed
0053  * from the lookup list by calling drm_privacy_screen_lookup_remove().
0054  */
0055 void drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup *lookup)
0056 {
0057     mutex_lock(&drm_privacy_screen_lookup_lock);
0058     list_add(&lookup->list, &drm_privacy_screen_lookup_list);
0059     mutex_unlock(&drm_privacy_screen_lookup_lock);
0060 }
0061 EXPORT_SYMBOL(drm_privacy_screen_lookup_add);
0062 
0063 /**
0064  * drm_privacy_screen_lookup_remove - remove an entry to the static
0065  *    privacy-screen lookup list
0066  * @lookup: lookup list entry to remove
0067  *
0068  * Remove an entry previously added with drm_privacy_screen_lookup_add()
0069  * from the static privacy-screen lookup list.
0070  */
0071 void drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup *lookup)
0072 {
0073     mutex_lock(&drm_privacy_screen_lookup_lock);
0074     list_del(&lookup->list);
0075     mutex_unlock(&drm_privacy_screen_lookup_lock);
0076 }
0077 EXPORT_SYMBOL(drm_privacy_screen_lookup_remove);
0078 
0079 /*** drm_privacy_screen_consumer.h functions ***/
0080 
0081 static struct drm_privacy_screen *drm_privacy_screen_get_by_name(
0082     const char *name)
0083 {
0084     struct drm_privacy_screen *priv;
0085     struct device *dev = NULL;
0086 
0087     mutex_lock(&drm_privacy_screen_devs_lock);
0088 
0089     list_for_each_entry(priv, &drm_privacy_screen_devs, list) {
0090         if (strcmp(dev_name(&priv->dev), name) == 0) {
0091             dev = get_device(&priv->dev);
0092             break;
0093         }
0094     }
0095 
0096     mutex_unlock(&drm_privacy_screen_devs_lock);
0097 
0098     return dev ? to_drm_privacy_screen(dev) : NULL;
0099 }
0100 
0101 /**
0102  * drm_privacy_screen_get - get a privacy-screen provider
0103  * @dev: consumer-device for which to get a privacy-screen provider
0104  * @con_id: (video)connector name for which to get a privacy-screen provider
0105  *
0106  * Get a privacy-screen provider for a privacy-screen attached to the
0107  * display described by the @dev and @con_id parameters.
0108  *
0109  * Return:
0110  * * A pointer to a &struct drm_privacy_screen on success.
0111  * * ERR_PTR(-ENODEV) if no matching privacy-screen is found
0112  * * ERR_PTR(-EPROBE_DEFER) if there is a matching privacy-screen,
0113  *                          but it has not been registered yet.
0114  */
0115 struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
0116                           const char *con_id)
0117 {
0118     const char *dev_id = dev ? dev_name(dev) : NULL;
0119     struct drm_privacy_screen_lookup *l;
0120     struct drm_privacy_screen *priv;
0121     const char *provider = NULL;
0122     int match, best = -1;
0123 
0124     /*
0125      * For now we only support using a static lookup table, which is
0126      * populated by the drm_privacy_screen_arch_init() call. This should
0127      * be extended with device-tree / fw_node lookup when support is added
0128      * for device-tree using hardware with a privacy-screen.
0129      *
0130      * The lookup algorithm was shamelessly taken from the clock
0131      * framework:
0132      *
0133      * We do slightly fuzzy matching here:
0134      *  An entry with a NULL ID is assumed to be a wildcard.
0135      *  If an entry has a device ID, it must match
0136      *  If an entry has a connection ID, it must match
0137      * Then we take the most specific entry - with the following order
0138      * of precedence: dev+con > dev only > con only.
0139      */
0140     mutex_lock(&drm_privacy_screen_lookup_lock);
0141 
0142     list_for_each_entry(l, &drm_privacy_screen_lookup_list, list) {
0143         match = 0;
0144 
0145         if (l->dev_id) {
0146             if (!dev_id || strcmp(l->dev_id, dev_id))
0147                 continue;
0148 
0149             match += 2;
0150         }
0151 
0152         if (l->con_id) {
0153             if (!con_id || strcmp(l->con_id, con_id))
0154                 continue;
0155 
0156             match += 1;
0157         }
0158 
0159         if (match > best) {
0160             provider = l->provider;
0161             best = match;
0162         }
0163     }
0164 
0165     mutex_unlock(&drm_privacy_screen_lookup_lock);
0166 
0167     if (!provider)
0168         return ERR_PTR(-ENODEV);
0169 
0170     priv = drm_privacy_screen_get_by_name(provider);
0171     if (!priv)
0172         return ERR_PTR(-EPROBE_DEFER);
0173 
0174     return priv;
0175 }
0176 EXPORT_SYMBOL(drm_privacy_screen_get);
0177 
0178 /**
0179  * drm_privacy_screen_put - release a privacy-screen reference
0180  * @priv: privacy screen reference to release
0181  *
0182  * Release a privacy-screen provider reference gotten through
0183  * drm_privacy_screen_get(). May be called with a NULL or ERR_PTR,
0184  * in which case it is a no-op.
0185  */
0186 void drm_privacy_screen_put(struct drm_privacy_screen *priv)
0187 {
0188     if (IS_ERR_OR_NULL(priv))
0189         return;
0190 
0191     put_device(&priv->dev);
0192 }
0193 EXPORT_SYMBOL(drm_privacy_screen_put);
0194 
0195 /**
0196  * drm_privacy_screen_set_sw_state - set a privacy-screen's sw-state
0197  * @priv: privacy screen to set the sw-state for
0198  * @sw_state: new sw-state value to set
0199  *
0200  * Set the sw-state of a privacy screen. If the privacy-screen is not
0201  * in a locked hw-state, then the actual and hw-state of the privacy-screen
0202  * will be immediately updated to the new value. If the privacy-screen is
0203  * in a locked hw-state, then the new sw-state will be remembered as the
0204  * requested state to put the privacy-screen in when it becomes unlocked.
0205  *
0206  * Return: 0 on success, negative error code on failure.
0207  */
0208 int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
0209                     enum drm_privacy_screen_status sw_state)
0210 {
0211     int ret = 0;
0212 
0213     mutex_lock(&priv->lock);
0214 
0215     if (!priv->ops) {
0216         ret = -ENODEV;
0217         goto out;
0218     }
0219 
0220     /*
0221      * As per the DRM connector properties documentation, setting the
0222      * sw_state while the hw_state is locked is allowed. In this case
0223      * it is a no-op other then storing the new sw_state so that it
0224      * can be honored when the state gets unlocked.
0225      * Also skip the set if the hw already is in the desired state.
0226      */
0227     if (priv->hw_state >= PRIVACY_SCREEN_DISABLED_LOCKED ||
0228         priv->hw_state == sw_state) {
0229         priv->sw_state = sw_state;
0230         goto out;
0231     }
0232 
0233     ret = priv->ops->set_sw_state(priv, sw_state);
0234 out:
0235     mutex_unlock(&priv->lock);
0236     return ret;
0237 }
0238 EXPORT_SYMBOL(drm_privacy_screen_set_sw_state);
0239 
0240 /**
0241  * drm_privacy_screen_get_state - get privacy-screen's current state
0242  * @priv: privacy screen to get the state for
0243  * @sw_state_ret: address where to store the privacy-screens current sw-state
0244  * @hw_state_ret: address where to store the privacy-screens current hw-state
0245  *
0246  * Get the current state of a privacy-screen, both the sw-state and the
0247  * hw-state.
0248  */
0249 void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
0250                   enum drm_privacy_screen_status *sw_state_ret,
0251                   enum drm_privacy_screen_status *hw_state_ret)
0252 {
0253     mutex_lock(&priv->lock);
0254     *sw_state_ret = priv->sw_state;
0255     *hw_state_ret = priv->hw_state;
0256     mutex_unlock(&priv->lock);
0257 }
0258 EXPORT_SYMBOL(drm_privacy_screen_get_state);
0259 
0260 /**
0261  * drm_privacy_screen_register_notifier - register a notifier
0262  * @priv: Privacy screen to register the notifier with
0263  * @nb: Notifier-block for the notifier to register
0264  *
0265  * Register a notifier with the privacy-screen to be notified of changes made
0266  * to the privacy-screen state from outside of the privacy-screen class.
0267  * E.g. the state may be changed by the hardware itself in response to a
0268  * hotkey press.
0269  *
0270  * The notifier is called with no locks held. The new hw_state and sw_state
0271  * can be retrieved using the drm_privacy_screen_get_state() function.
0272  * A pointer to the drm_privacy_screen's struct is passed as the ``void *data``
0273  * argument of the notifier_block's notifier_call.
0274  *
0275  * The notifier will NOT be called when changes are made through
0276  * drm_privacy_screen_set_sw_state(). It is only called for external changes.
0277  *
0278  * Return: 0 on success, negative error code on failure.
0279  */
0280 int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv,
0281                      struct notifier_block *nb)
0282 {
0283     return blocking_notifier_chain_register(&priv->notifier_head, nb);
0284 }
0285 EXPORT_SYMBOL(drm_privacy_screen_register_notifier);
0286 
0287 /**
0288  * drm_privacy_screen_unregister_notifier - unregister a notifier
0289  * @priv: Privacy screen to register the notifier with
0290  * @nb: Notifier-block for the notifier to register
0291  *
0292  * Unregister a notifier registered with drm_privacy_screen_register_notifier().
0293  *
0294  * Return: 0 on success, negative error code on failure.
0295  */
0296 int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv,
0297                        struct notifier_block *nb)
0298 {
0299     return blocking_notifier_chain_unregister(&priv->notifier_head, nb);
0300 }
0301 EXPORT_SYMBOL(drm_privacy_screen_unregister_notifier);
0302 
0303 /*** drm_privacy_screen_driver.h functions ***/
0304 
0305 static ssize_t sw_state_show(struct device *dev,
0306                  struct device_attribute *attr, char *buf)
0307 {
0308     struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0309     const char * const sw_state_names[] = {
0310         "Disabled",
0311         "Enabled",
0312     };
0313     ssize_t ret;
0314 
0315     mutex_lock(&priv->lock);
0316 
0317     if (!priv->ops)
0318         ret = -ENODEV;
0319     else if (WARN_ON(priv->sw_state >= ARRAY_SIZE(sw_state_names)))
0320         ret = -ENXIO;
0321     else
0322         ret = sprintf(buf, "%s\n", sw_state_names[priv->sw_state]);
0323 
0324     mutex_unlock(&priv->lock);
0325     return ret;
0326 }
0327 /*
0328  * RO: Do not allow setting the sw_state through sysfs, this MUST be done
0329  * through the drm_properties on the drm_connector.
0330  */
0331 static DEVICE_ATTR_RO(sw_state);
0332 
0333 static ssize_t hw_state_show(struct device *dev,
0334                  struct device_attribute *attr, char *buf)
0335 {
0336     struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0337     const char * const hw_state_names[] = {
0338         "Disabled",
0339         "Enabled",
0340         "Disabled, locked",
0341         "Enabled, locked",
0342     };
0343     ssize_t ret;
0344 
0345     mutex_lock(&priv->lock);
0346 
0347     if (!priv->ops)
0348         ret = -ENODEV;
0349     else if (WARN_ON(priv->hw_state >= ARRAY_SIZE(hw_state_names)))
0350         ret = -ENXIO;
0351     else
0352         ret = sprintf(buf, "%s\n", hw_state_names[priv->hw_state]);
0353 
0354     mutex_unlock(&priv->lock);
0355     return ret;
0356 }
0357 static DEVICE_ATTR_RO(hw_state);
0358 
0359 static struct attribute *drm_privacy_screen_attrs[] = {
0360     &dev_attr_sw_state.attr,
0361     &dev_attr_hw_state.attr,
0362     NULL
0363 };
0364 ATTRIBUTE_GROUPS(drm_privacy_screen);
0365 
0366 static struct device_type drm_privacy_screen_type = {
0367     .name = "privacy_screen",
0368     .groups = drm_privacy_screen_groups,
0369 };
0370 
0371 static void drm_privacy_screen_device_release(struct device *dev)
0372 {
0373     struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0374 
0375     kfree(priv);
0376 }
0377 
0378 /**
0379  * drm_privacy_screen_register - register a privacy-screen
0380  * @parent: parent-device for the privacy-screen
0381  * @ops: &struct drm_privacy_screen_ops pointer with ops for the privacy-screen
0382  * @data: Private data owned by the privacy screen provider
0383  *
0384  * Create and register a privacy-screen.
0385  *
0386  * Return:
0387  * * A pointer to the created privacy-screen on success.
0388  * * An ERR_PTR(errno) on failure.
0389  */
0390 struct drm_privacy_screen *drm_privacy_screen_register(
0391     struct device *parent, const struct drm_privacy_screen_ops *ops,
0392     void *data)
0393 {
0394     struct drm_privacy_screen *priv;
0395     int ret;
0396 
0397     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0398     if (!priv)
0399         return ERR_PTR(-ENOMEM);
0400 
0401     mutex_init(&priv->lock);
0402     BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head);
0403 
0404     priv->dev.class = drm_class;
0405     priv->dev.type = &drm_privacy_screen_type;
0406     priv->dev.parent = parent;
0407     priv->dev.release = drm_privacy_screen_device_release;
0408     dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent));
0409     priv->drvdata = data;
0410     priv->ops = ops;
0411 
0412     priv->ops->get_hw_state(priv);
0413 
0414     ret = device_register(&priv->dev);
0415     if (ret) {
0416         put_device(&priv->dev);
0417         return ERR_PTR(ret);
0418     }
0419 
0420     mutex_lock(&drm_privacy_screen_devs_lock);
0421     list_add(&priv->list, &drm_privacy_screen_devs);
0422     mutex_unlock(&drm_privacy_screen_devs_lock);
0423 
0424     return priv;
0425 }
0426 EXPORT_SYMBOL(drm_privacy_screen_register);
0427 
0428 /**
0429  * drm_privacy_screen_unregister - unregister privacy-screen
0430  * @priv: privacy-screen to unregister
0431  *
0432  * Unregister a privacy-screen registered with drm_privacy_screen_register().
0433  * May be called with a NULL or ERR_PTR, in which case it is a no-op.
0434  */
0435 void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
0436 {
0437     if (IS_ERR_OR_NULL(priv))
0438         return;
0439 
0440     mutex_lock(&drm_privacy_screen_devs_lock);
0441     list_del(&priv->list);
0442     mutex_unlock(&drm_privacy_screen_devs_lock);
0443 
0444     mutex_lock(&priv->lock);
0445     priv->drvdata = NULL;
0446     priv->ops = NULL;
0447     mutex_unlock(&priv->lock);
0448 
0449     device_unregister(&priv->dev);
0450 }
0451 EXPORT_SYMBOL(drm_privacy_screen_unregister);
0452 
0453 /**
0454  * drm_privacy_screen_call_notifier_chain - notify consumers of state change
0455  * @priv: Privacy screen to register the notifier with
0456  *
0457  * A privacy-screen provider driver can call this functions upon external
0458  * changes to the privacy-screen state. E.g. the state may be changed by the
0459  * hardware itself in response to a hotkey press.
0460  * This function must be called without holding the privacy-screen lock.
0461  * the driver must update sw_state and hw_state to reflect the new state before
0462  * calling this function.
0463  * The expected behavior from the driver upon receiving an external state
0464  * change event is: 1. Take the lock; 2. Update sw_state and hw_state;
0465  * 3. Release the lock. 4. Call drm_privacy_screen_call_notifier_chain().
0466  */
0467 void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv)
0468 {
0469     blocking_notifier_call_chain(&priv->notifier_head, 0, priv);
0470 }
0471 EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain);