1a1a98689SHans de Goede // SPDX-License-Identifier: MIT 2a1a98689SHans de Goede /* 3a1a98689SHans de Goede * Copyright (C) 2020 - 2021 Red Hat, Inc. 4a1a98689SHans de Goede * 5a1a98689SHans de Goede * Authors: 6a1a98689SHans de Goede * Hans de Goede <hdegoede@redhat.com> 7a1a98689SHans de Goede */ 8a1a98689SHans de Goede 9a1a98689SHans de Goede #include <linux/device.h> 10a1a98689SHans de Goede #include <linux/kernel.h> 11a1a98689SHans de Goede #include <linux/list.h> 12a1a98689SHans de Goede #include <linux/module.h> 13a1a98689SHans de Goede #include <linux/mutex.h> 14a1a98689SHans de Goede #include <linux/slab.h> 15a1a98689SHans de Goede #include <drm/drm_privacy_screen_machine.h> 16a1a98689SHans de Goede #include <drm/drm_privacy_screen_consumer.h> 17a1a98689SHans de Goede #include <drm/drm_privacy_screen_driver.h> 18a1a98689SHans de Goede #include "drm_internal.h" 19a1a98689SHans de Goede 20a1a98689SHans de Goede /** 21a1a98689SHans de Goede * DOC: overview 22a1a98689SHans de Goede * 23a1a98689SHans de Goede * This class allows non KMS drivers, from e.g. drivers/platform/x86 to 24a1a98689SHans de Goede * register a privacy-screen device, which the KMS drivers can then use 25a1a98689SHans de Goede * to implement the standard privacy-screen properties, see 26a1a98689SHans de Goede * :ref:`Standard Connector Properties<standard_connector_properties>`. 27a1a98689SHans de Goede * 28a1a98689SHans de Goede * KMS drivers using a privacy-screen class device are advised to use the 29a1a98689SHans de Goede * drm_connector_attach_privacy_screen_provider() and 30a1a98689SHans de Goede * drm_connector_update_privacy_screen() helpers for dealing with this. 31a1a98689SHans de Goede */ 32a1a98689SHans de Goede 33a1a98689SHans de Goede #define to_drm_privacy_screen(dev) \ 34a1a98689SHans de Goede container_of(dev, struct drm_privacy_screen, dev) 35a1a98689SHans de Goede 36a1a98689SHans de Goede static DEFINE_MUTEX(drm_privacy_screen_lookup_lock); 37a1a98689SHans de Goede static LIST_HEAD(drm_privacy_screen_lookup_list); 38a1a98689SHans de Goede 39a1a98689SHans de Goede static DEFINE_MUTEX(drm_privacy_screen_devs_lock); 40a1a98689SHans de Goede static LIST_HEAD(drm_privacy_screen_devs); 41a1a98689SHans de Goede 42a1a98689SHans de Goede /*** drm_privacy_screen_machine.h functions ***/ 43a1a98689SHans de Goede 44a1a98689SHans de Goede /** 45a1a98689SHans de Goede * drm_privacy_screen_lookup_add - add an entry to the static privacy-screen 46a1a98689SHans de Goede * lookup list 47a1a98689SHans de Goede * @lookup: lookup list entry to add 48a1a98689SHans de Goede * 49a1a98689SHans de Goede * Add an entry to the static privacy-screen lookup list. Note the 50a1a98689SHans de Goede * &struct list_head which is part of the &struct drm_privacy_screen_lookup 51a1a98689SHans de Goede * gets added to a list owned by the privacy-screen core. So the passed in 52a1a98689SHans de Goede * &struct drm_privacy_screen_lookup must not be free-ed until it is removed 53a1a98689SHans de Goede * from the lookup list by calling drm_privacy_screen_lookup_remove(). 54a1a98689SHans de Goede */ 55a1a98689SHans de Goede void drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup *lookup) 56a1a98689SHans de Goede { 57a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_lookup_lock); 58a1a98689SHans de Goede list_add(&lookup->list, &drm_privacy_screen_lookup_list); 59a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_lookup_lock); 60a1a98689SHans de Goede } 61a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_lookup_add); 62a1a98689SHans de Goede 63a1a98689SHans de Goede /** 64a1a98689SHans de Goede * drm_privacy_screen_lookup_remove - remove an entry to the static 65a1a98689SHans de Goede * privacy-screen lookup list 66a1a98689SHans de Goede * @lookup: lookup list entry to remove 67a1a98689SHans de Goede * 68a1a98689SHans de Goede * Remove an entry previously added with drm_privacy_screen_lookup_add() 69a1a98689SHans de Goede * from the static privacy-screen lookup list. 70a1a98689SHans de Goede */ 71a1a98689SHans de Goede void drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup *lookup) 72a1a98689SHans de Goede { 73a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_lookup_lock); 74a1a98689SHans de Goede list_del(&lookup->list); 75a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_lookup_lock); 76a1a98689SHans de Goede } 77a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_lookup_remove); 78a1a98689SHans de Goede 79a1a98689SHans de Goede /*** drm_privacy_screen_consumer.h functions ***/ 80a1a98689SHans de Goede 81a1a98689SHans de Goede static struct drm_privacy_screen *drm_privacy_screen_get_by_name( 82a1a98689SHans de Goede const char *name) 83a1a98689SHans de Goede { 84a1a98689SHans de Goede struct drm_privacy_screen *priv; 85a1a98689SHans de Goede struct device *dev = NULL; 86a1a98689SHans de Goede 87a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_devs_lock); 88a1a98689SHans de Goede 89a1a98689SHans de Goede list_for_each_entry(priv, &drm_privacy_screen_devs, list) { 90a1a98689SHans de Goede if (strcmp(dev_name(&priv->dev), name) == 0) { 91a1a98689SHans de Goede dev = get_device(&priv->dev); 92a1a98689SHans de Goede break; 93a1a98689SHans de Goede } 94a1a98689SHans de Goede } 95a1a98689SHans de Goede 96a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_devs_lock); 97a1a98689SHans de Goede 98a1a98689SHans de Goede return dev ? to_drm_privacy_screen(dev) : NULL; 99a1a98689SHans de Goede } 100a1a98689SHans de Goede 101a1a98689SHans de Goede /** 102a1a98689SHans de Goede * drm_privacy_screen_get - get a privacy-screen provider 103a1a98689SHans de Goede * @dev: consumer-device for which to get a privacy-screen provider 104a1a98689SHans de Goede * @con_id: (video)connector name for which to get a privacy-screen provider 105a1a98689SHans de Goede * 106a1a98689SHans de Goede * Get a privacy-screen provider for a privacy-screen attached to the 107a1a98689SHans de Goede * display described by the @dev and @con_id parameters. 108a1a98689SHans de Goede * 109a1a98689SHans de Goede * Return: 110a1a98689SHans de Goede * * A pointer to a &struct drm_privacy_screen on success. 111a1a98689SHans de Goede * * ERR_PTR(-ENODEV) if no matching privacy-screen is found 112a1a98689SHans de Goede * * ERR_PTR(-EPROBE_DEFER) if there is a matching privacy-screen, 113a1a98689SHans de Goede * but it has not been registered yet. 114a1a98689SHans de Goede */ 115a1a98689SHans de Goede struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev, 116a1a98689SHans de Goede const char *con_id) 117a1a98689SHans de Goede { 118a1a98689SHans de Goede const char *dev_id = dev ? dev_name(dev) : NULL; 119a1a98689SHans de Goede struct drm_privacy_screen_lookup *l; 120a1a98689SHans de Goede struct drm_privacy_screen *priv; 121a1a98689SHans de Goede const char *provider = NULL; 122a1a98689SHans de Goede int match, best = -1; 123a1a98689SHans de Goede 124a1a98689SHans de Goede /* 125a1a98689SHans de Goede * For now we only support using a static lookup table, which is 126a1a98689SHans de Goede * populated by the drm_privacy_screen_arch_init() call. This should 127a1a98689SHans de Goede * be extended with device-tree / fw_node lookup when support is added 128a1a98689SHans de Goede * for device-tree using hardware with a privacy-screen. 129a1a98689SHans de Goede * 130a1a98689SHans de Goede * The lookup algorithm was shamelessly taken from the clock 131a1a98689SHans de Goede * framework: 132a1a98689SHans de Goede * 133a1a98689SHans de Goede * We do slightly fuzzy matching here: 134a1a98689SHans de Goede * An entry with a NULL ID is assumed to be a wildcard. 135a1a98689SHans de Goede * If an entry has a device ID, it must match 136a1a98689SHans de Goede * If an entry has a connection ID, it must match 137a1a98689SHans de Goede * Then we take the most specific entry - with the following order 138a1a98689SHans de Goede * of precedence: dev+con > dev only > con only. 139a1a98689SHans de Goede */ 140a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_lookup_lock); 141a1a98689SHans de Goede 142a1a98689SHans de Goede list_for_each_entry(l, &drm_privacy_screen_lookup_list, list) { 143a1a98689SHans de Goede match = 0; 144a1a98689SHans de Goede 145a1a98689SHans de Goede if (l->dev_id) { 146a1a98689SHans de Goede if (!dev_id || strcmp(l->dev_id, dev_id)) 147a1a98689SHans de Goede continue; 148a1a98689SHans de Goede 149a1a98689SHans de Goede match += 2; 150a1a98689SHans de Goede } 151a1a98689SHans de Goede 152a1a98689SHans de Goede if (l->con_id) { 153a1a98689SHans de Goede if (!con_id || strcmp(l->con_id, con_id)) 154a1a98689SHans de Goede continue; 155a1a98689SHans de Goede 156a1a98689SHans de Goede match += 1; 157a1a98689SHans de Goede } 158a1a98689SHans de Goede 159a1a98689SHans de Goede if (match > best) { 160a1a98689SHans de Goede provider = l->provider; 161a1a98689SHans de Goede best = match; 162a1a98689SHans de Goede } 163a1a98689SHans de Goede } 164a1a98689SHans de Goede 165a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_lookup_lock); 166a1a98689SHans de Goede 167a1a98689SHans de Goede if (!provider) 168a1a98689SHans de Goede return ERR_PTR(-ENODEV); 169a1a98689SHans de Goede 170a1a98689SHans de Goede priv = drm_privacy_screen_get_by_name(provider); 171a1a98689SHans de Goede if (!priv) 172a1a98689SHans de Goede return ERR_PTR(-EPROBE_DEFER); 173a1a98689SHans de Goede 174a1a98689SHans de Goede return priv; 175a1a98689SHans de Goede } 176a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_get); 177a1a98689SHans de Goede 178a1a98689SHans de Goede /** 179a1a98689SHans de Goede * drm_privacy_screen_put - release a privacy-screen reference 180a1a98689SHans de Goede * @priv: privacy screen reference to release 181a1a98689SHans de Goede * 182a1a98689SHans de Goede * Release a privacy-screen provider reference gotten through 183a1a98689SHans de Goede * drm_privacy_screen_get(). May be called with a NULL or ERR_PTR, 184a1a98689SHans de Goede * in which case it is a no-op. 185a1a98689SHans de Goede */ 186a1a98689SHans de Goede void drm_privacy_screen_put(struct drm_privacy_screen *priv) 187a1a98689SHans de Goede { 188a1a98689SHans de Goede if (IS_ERR_OR_NULL(priv)) 189a1a98689SHans de Goede return; 190a1a98689SHans de Goede 191a1a98689SHans de Goede put_device(&priv->dev); 192a1a98689SHans de Goede } 193a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_put); 194a1a98689SHans de Goede 195a1a98689SHans de Goede /** 196a1a98689SHans de Goede * drm_privacy_screen_set_sw_state - set a privacy-screen's sw-state 197a1a98689SHans de Goede * @priv: privacy screen to set the sw-state for 198a1a98689SHans de Goede * @sw_state: new sw-state value to set 199a1a98689SHans de Goede * 200a1a98689SHans de Goede * Set the sw-state of a privacy screen. If the privacy-screen is not 201a1a98689SHans de Goede * in a locked hw-state, then the actual and hw-state of the privacy-screen 202a1a98689SHans de Goede * will be immediately updated to the new value. If the privacy-screen is 203a1a98689SHans de Goede * in a locked hw-state, then the new sw-state will be remembered as the 204a1a98689SHans de Goede * requested state to put the privacy-screen in when it becomes unlocked. 205a1a98689SHans de Goede * 206a1a98689SHans de Goede * Return: 0 on success, negative error code on failure. 207a1a98689SHans de Goede */ 208a1a98689SHans de Goede int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv, 209a1a98689SHans de Goede enum drm_privacy_screen_status sw_state) 210a1a98689SHans de Goede { 211a1a98689SHans de Goede int ret = 0; 212a1a98689SHans de Goede 213a1a98689SHans de Goede mutex_lock(&priv->lock); 214a1a98689SHans de Goede 215a1a98689SHans de Goede if (!priv->ops) { 216a1a98689SHans de Goede ret = -ENODEV; 217a1a98689SHans de Goede goto out; 218a1a98689SHans de Goede } 219a1a98689SHans de Goede 220a1a98689SHans de Goede /* 221a1a98689SHans de Goede * As per the DRM connector properties documentation, setting the 222a1a98689SHans de Goede * sw_state while the hw_state is locked is allowed. In this case 223a1a98689SHans de Goede * it is a no-op other then storing the new sw_state so that it 224a1a98689SHans de Goede * can be honored when the state gets unlocked. 225a1a98689SHans de Goede * Also skip the set if the hw already is in the desired state. 226a1a98689SHans de Goede */ 227a1a98689SHans de Goede if (priv->hw_state >= PRIVACY_SCREEN_DISABLED_LOCKED || 228a1a98689SHans de Goede priv->hw_state == sw_state) { 229a1a98689SHans de Goede priv->sw_state = sw_state; 230a1a98689SHans de Goede goto out; 231a1a98689SHans de Goede } 232a1a98689SHans de Goede 233a1a98689SHans de Goede ret = priv->ops->set_sw_state(priv, sw_state); 234a1a98689SHans de Goede out: 235a1a98689SHans de Goede mutex_unlock(&priv->lock); 236a1a98689SHans de Goede return ret; 237a1a98689SHans de Goede } 238a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_set_sw_state); 239a1a98689SHans de Goede 240a1a98689SHans de Goede /** 241a1a98689SHans de Goede * drm_privacy_screen_get_state - get privacy-screen's current state 242a1a98689SHans de Goede * @priv: privacy screen to get the state for 243a1a98689SHans de Goede * @sw_state_ret: address where to store the privacy-screens current sw-state 244a1a98689SHans de Goede * @hw_state_ret: address where to store the privacy-screens current hw-state 245a1a98689SHans de Goede * 246a1a98689SHans de Goede * Get the current state of a privacy-screen, both the sw-state and the 247a1a98689SHans de Goede * hw-state. 248a1a98689SHans de Goede */ 249a1a98689SHans de Goede void drm_privacy_screen_get_state(struct drm_privacy_screen *priv, 250a1a98689SHans de Goede enum drm_privacy_screen_status *sw_state_ret, 251a1a98689SHans de Goede enum drm_privacy_screen_status *hw_state_ret) 252a1a98689SHans de Goede { 253a1a98689SHans de Goede mutex_lock(&priv->lock); 254a1a98689SHans de Goede *sw_state_ret = priv->sw_state; 255a1a98689SHans de Goede *hw_state_ret = priv->hw_state; 256a1a98689SHans de Goede mutex_unlock(&priv->lock); 257a1a98689SHans de Goede } 258a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_get_state); 259a1a98689SHans de Goede 2608a12b170SHans de Goede /** 2618a12b170SHans de Goede * drm_privacy_screen_register_notifier - register a notifier 2628a12b170SHans de Goede * @priv: Privacy screen to register the notifier with 2638a12b170SHans de Goede * @nb: Notifier-block for the notifier to register 2648a12b170SHans de Goede * 2658a12b170SHans de Goede * Register a notifier with the privacy-screen to be notified of changes made 2668a12b170SHans de Goede * to the privacy-screen state from outside of the privacy-screen class. 2678a12b170SHans de Goede * E.g. the state may be changed by the hardware itself in response to a 2688a12b170SHans de Goede * hotkey press. 2698a12b170SHans de Goede * 2708a12b170SHans de Goede * The notifier is called with no locks held. The new hw_state and sw_state 2718a12b170SHans de Goede * can be retrieved using the drm_privacy_screen_get_state() function. 272*200e8e3eSHans de Goede * A pointer to the drm_privacy_screen's struct is passed as the ``void *data`` 2738a12b170SHans de Goede * argument of the notifier_block's notifier_call. 2748a12b170SHans de Goede * 2758a12b170SHans de Goede * The notifier will NOT be called when changes are made through 2768a12b170SHans de Goede * drm_privacy_screen_set_sw_state(). It is only called for external changes. 2778a12b170SHans de Goede * 2788a12b170SHans de Goede * Return: 0 on success, negative error code on failure. 2798a12b170SHans de Goede */ 2808a12b170SHans de Goede int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv, 2818a12b170SHans de Goede struct notifier_block *nb) 2828a12b170SHans de Goede { 2838a12b170SHans de Goede return blocking_notifier_chain_register(&priv->notifier_head, nb); 2848a12b170SHans de Goede } 2858a12b170SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_register_notifier); 2868a12b170SHans de Goede 2878a12b170SHans de Goede /** 2888a12b170SHans de Goede * drm_privacy_screen_unregister_notifier - unregister a notifier 2898a12b170SHans de Goede * @priv: Privacy screen to register the notifier with 2908a12b170SHans de Goede * @nb: Notifier-block for the notifier to register 2918a12b170SHans de Goede * 2928a12b170SHans de Goede * Unregister a notifier registered with drm_privacy_screen_register_notifier(). 2938a12b170SHans de Goede * 2948a12b170SHans de Goede * Return: 0 on success, negative error code on failure. 2958a12b170SHans de Goede */ 2968a12b170SHans de Goede int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv, 2978a12b170SHans de Goede struct notifier_block *nb) 2988a12b170SHans de Goede { 2998a12b170SHans de Goede return blocking_notifier_chain_unregister(&priv->notifier_head, nb); 3008a12b170SHans de Goede } 3018a12b170SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_unregister_notifier); 3028a12b170SHans de Goede 303a1a98689SHans de Goede /*** drm_privacy_screen_driver.h functions ***/ 304a1a98689SHans de Goede 305a1a98689SHans de Goede static ssize_t sw_state_show(struct device *dev, 306a1a98689SHans de Goede struct device_attribute *attr, char *buf) 307a1a98689SHans de Goede { 308a1a98689SHans de Goede struct drm_privacy_screen *priv = to_drm_privacy_screen(dev); 309a1a98689SHans de Goede const char * const sw_state_names[] = { 310a1a98689SHans de Goede "Disabled", 311a1a98689SHans de Goede "Enabled", 312a1a98689SHans de Goede }; 313a1a98689SHans de Goede ssize_t ret; 314a1a98689SHans de Goede 315a1a98689SHans de Goede mutex_lock(&priv->lock); 316a1a98689SHans de Goede 317a1a98689SHans de Goede if (!priv->ops) 318a1a98689SHans de Goede ret = -ENODEV; 319a1a98689SHans de Goede else if (WARN_ON(priv->sw_state >= ARRAY_SIZE(sw_state_names))) 320a1a98689SHans de Goede ret = -ENXIO; 321a1a98689SHans de Goede else 322a1a98689SHans de Goede ret = sprintf(buf, "%s\n", sw_state_names[priv->sw_state]); 323a1a98689SHans de Goede 324a1a98689SHans de Goede mutex_unlock(&priv->lock); 325a1a98689SHans de Goede return ret; 326a1a98689SHans de Goede } 327a1a98689SHans de Goede /* 328a1a98689SHans de Goede * RO: Do not allow setting the sw_state through sysfs, this MUST be done 329a1a98689SHans de Goede * through the drm_properties on the drm_connector. 330a1a98689SHans de Goede */ 331a1a98689SHans de Goede static DEVICE_ATTR_RO(sw_state); 332a1a98689SHans de Goede 333a1a98689SHans de Goede static ssize_t hw_state_show(struct device *dev, 334a1a98689SHans de Goede struct device_attribute *attr, char *buf) 335a1a98689SHans de Goede { 336a1a98689SHans de Goede struct drm_privacy_screen *priv = to_drm_privacy_screen(dev); 337a1a98689SHans de Goede const char * const hw_state_names[] = { 338a1a98689SHans de Goede "Disabled", 339a1a98689SHans de Goede "Enabled", 340a1a98689SHans de Goede "Disabled, locked", 341a1a98689SHans de Goede "Enabled, locked", 342a1a98689SHans de Goede }; 343a1a98689SHans de Goede ssize_t ret; 344a1a98689SHans de Goede 345a1a98689SHans de Goede mutex_lock(&priv->lock); 346a1a98689SHans de Goede 347a1a98689SHans de Goede if (!priv->ops) 348a1a98689SHans de Goede ret = -ENODEV; 349a1a98689SHans de Goede else if (WARN_ON(priv->hw_state >= ARRAY_SIZE(hw_state_names))) 350a1a98689SHans de Goede ret = -ENXIO; 351a1a98689SHans de Goede else 352a1a98689SHans de Goede ret = sprintf(buf, "%s\n", hw_state_names[priv->hw_state]); 353a1a98689SHans de Goede 354a1a98689SHans de Goede mutex_unlock(&priv->lock); 355a1a98689SHans de Goede return ret; 356a1a98689SHans de Goede } 357a1a98689SHans de Goede static DEVICE_ATTR_RO(hw_state); 358a1a98689SHans de Goede 359a1a98689SHans de Goede static struct attribute *drm_privacy_screen_attrs[] = { 360a1a98689SHans de Goede &dev_attr_sw_state.attr, 361a1a98689SHans de Goede &dev_attr_hw_state.attr, 362a1a98689SHans de Goede NULL 363a1a98689SHans de Goede }; 364a1a98689SHans de Goede ATTRIBUTE_GROUPS(drm_privacy_screen); 365a1a98689SHans de Goede 366a1a98689SHans de Goede static struct device_type drm_privacy_screen_type = { 367a1a98689SHans de Goede .name = "privacy_screen", 368a1a98689SHans de Goede .groups = drm_privacy_screen_groups, 369a1a98689SHans de Goede }; 370a1a98689SHans de Goede 371a1a98689SHans de Goede static void drm_privacy_screen_device_release(struct device *dev) 372a1a98689SHans de Goede { 373a1a98689SHans de Goede struct drm_privacy_screen *priv = to_drm_privacy_screen(dev); 374a1a98689SHans de Goede 375a1a98689SHans de Goede kfree(priv); 376a1a98689SHans de Goede } 377a1a98689SHans de Goede 378a1a98689SHans de Goede /** 379a1a98689SHans de Goede * drm_privacy_screen_register - register a privacy-screen 380a1a98689SHans de Goede * @parent: parent-device for the privacy-screen 381a1a98689SHans de Goede * @ops: &struct drm_privacy_screen_ops pointer with ops for the privacy-screen 382a1a98689SHans de Goede * 383a1a98689SHans de Goede * Create and register a privacy-screen. 384a1a98689SHans de Goede * 385a1a98689SHans de Goede * Return: 386a1a98689SHans de Goede * * A pointer to the created privacy-screen on success. 387a1a98689SHans de Goede * * An ERR_PTR(errno) on failure. 388a1a98689SHans de Goede */ 389a1a98689SHans de Goede struct drm_privacy_screen *drm_privacy_screen_register( 390a1a98689SHans de Goede struct device *parent, const struct drm_privacy_screen_ops *ops) 391a1a98689SHans de Goede { 392a1a98689SHans de Goede struct drm_privacy_screen *priv; 393a1a98689SHans de Goede int ret; 394a1a98689SHans de Goede 395a1a98689SHans de Goede priv = kzalloc(sizeof(*priv), GFP_KERNEL); 396a1a98689SHans de Goede if (!priv) 397a1a98689SHans de Goede return ERR_PTR(-ENOMEM); 398a1a98689SHans de Goede 399a1a98689SHans de Goede mutex_init(&priv->lock); 4008a12b170SHans de Goede BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head); 401a1a98689SHans de Goede 402a1a98689SHans de Goede priv->dev.class = drm_class; 403a1a98689SHans de Goede priv->dev.type = &drm_privacy_screen_type; 404a1a98689SHans de Goede priv->dev.parent = parent; 405a1a98689SHans de Goede priv->dev.release = drm_privacy_screen_device_release; 406a1a98689SHans de Goede dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); 407a1a98689SHans de Goede priv->ops = ops; 408a1a98689SHans de Goede 409a1a98689SHans de Goede priv->ops->get_hw_state(priv); 410a1a98689SHans de Goede 411a1a98689SHans de Goede ret = device_register(&priv->dev); 412a1a98689SHans de Goede if (ret) { 413a1a98689SHans de Goede put_device(&priv->dev); 414a1a98689SHans de Goede return ERR_PTR(ret); 415a1a98689SHans de Goede } 416a1a98689SHans de Goede 417a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_devs_lock); 418a1a98689SHans de Goede list_add(&priv->list, &drm_privacy_screen_devs); 419a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_devs_lock); 420a1a98689SHans de Goede 421a1a98689SHans de Goede return priv; 422a1a98689SHans de Goede } 423a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_register); 424a1a98689SHans de Goede 425a1a98689SHans de Goede /** 426a1a98689SHans de Goede * drm_privacy_screen_unregister - unregister privacy-screen 427a1a98689SHans de Goede * @priv: privacy-screen to unregister 428a1a98689SHans de Goede * 429a1a98689SHans de Goede * Unregister a privacy-screen registered with drm_privacy_screen_register(). 430a1a98689SHans de Goede * May be called with a NULL or ERR_PTR, in which case it is a no-op. 431a1a98689SHans de Goede */ 432a1a98689SHans de Goede void drm_privacy_screen_unregister(struct drm_privacy_screen *priv) 433a1a98689SHans de Goede { 434a1a98689SHans de Goede if (IS_ERR_OR_NULL(priv)) 435a1a98689SHans de Goede return; 436a1a98689SHans de Goede 437a1a98689SHans de Goede mutex_lock(&drm_privacy_screen_devs_lock); 438a1a98689SHans de Goede list_del(&priv->list); 439a1a98689SHans de Goede mutex_unlock(&drm_privacy_screen_devs_lock); 440a1a98689SHans de Goede 441a1a98689SHans de Goede mutex_lock(&priv->lock); 442a1a98689SHans de Goede priv->ops = NULL; 443a1a98689SHans de Goede mutex_unlock(&priv->lock); 444a1a98689SHans de Goede 445a1a98689SHans de Goede device_unregister(&priv->dev); 446a1a98689SHans de Goede } 447a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_unregister); 4488a12b170SHans de Goede 4498a12b170SHans de Goede /** 4508a12b170SHans de Goede * drm_privacy_screen_call_notifier_chain - notify consumers of state change 4518a12b170SHans de Goede * @priv: Privacy screen to register the notifier with 4528a12b170SHans de Goede * 4538a12b170SHans de Goede * A privacy-screen provider driver can call this functions upon external 4548a12b170SHans de Goede * changes to the privacy-screen state. E.g. the state may be changed by the 4558a12b170SHans de Goede * hardware itself in response to a hotkey press. 4568a12b170SHans de Goede * This function must be called without holding the privacy-screen lock. 4578a12b170SHans de Goede * the driver must update sw_state and hw_state to reflect the new state before 4588a12b170SHans de Goede * calling this function. 4598a12b170SHans de Goede * The expected behavior from the driver upon receiving an external state 4608a12b170SHans de Goede * change event is: 1. Take the lock; 2. Update sw_state and hw_state; 4618a12b170SHans de Goede * 3. Release the lock. 4. Call drm_privacy_screen_call_notifier_chain(). 4628a12b170SHans de Goede */ 4638a12b170SHans de Goede void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv) 4648a12b170SHans de Goede { 4658a12b170SHans de Goede blocking_notifier_call_chain(&priv->notifier_head, 0, priv); 4668a12b170SHans de Goede } 4678a12b170SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain); 468