xref: /openbmc/linux/drivers/gpu/drm/drm_privacy_screen.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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  */
drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup * lookup)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  */
drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup * lookup)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 
drm_privacy_screen_get_by_name(const char * name)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  */
drm_privacy_screen_get(struct device * dev,const char * con_id)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  */
drm_privacy_screen_put(struct drm_privacy_screen * priv)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  */
drm_privacy_screen_set_sw_state(struct drm_privacy_screen * priv,enum drm_privacy_screen_status sw_state)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  */
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)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  */
drm_privacy_screen_register_notifier(struct drm_privacy_screen * priv,struct notifier_block * nb)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  */
drm_privacy_screen_unregister_notifier(struct drm_privacy_screen * priv,struct notifier_block * nb)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 
sw_state_show(struct device * dev,struct device_attribute * attr,char * buf)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 
hw_state_show(struct device * dev,struct device_attribute * attr,char * buf)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 
drm_privacy_screen_device_release(struct device * dev)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
382ccbeca4cSHans de Goede  * @data: Private data owned by the privacy screen provider
383a1a98689SHans de Goede  *
384a1a98689SHans de Goede  * Create and register a privacy-screen.
385a1a98689SHans de Goede  *
386a1a98689SHans de Goede  * Return:
387a1a98689SHans de Goede  * * A pointer to the created privacy-screen on success.
388a1a98689SHans de Goede  * * An ERR_PTR(errno) on failure.
389a1a98689SHans de Goede  */
drm_privacy_screen_register(struct device * parent,const struct drm_privacy_screen_ops * ops,void * data)390a1a98689SHans de Goede struct drm_privacy_screen *drm_privacy_screen_register(
39130598d92SRajat Jain 	struct device *parent, const struct drm_privacy_screen_ops *ops,
39230598d92SRajat Jain 	void *data)
393a1a98689SHans de Goede {
394a1a98689SHans de Goede 	struct drm_privacy_screen *priv;
395a1a98689SHans de Goede 	int ret;
396a1a98689SHans de Goede 
397a1a98689SHans de Goede 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
398a1a98689SHans de Goede 	if (!priv)
399a1a98689SHans de Goede 		return ERR_PTR(-ENOMEM);
400a1a98689SHans de Goede 
401a1a98689SHans de Goede 	mutex_init(&priv->lock);
4028a12b170SHans de Goede 	BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head);
403a1a98689SHans de Goede 
404a1a98689SHans de Goede 	priv->dev.class = drm_class;
405a1a98689SHans de Goede 	priv->dev.type = &drm_privacy_screen_type;
406a1a98689SHans de Goede 	priv->dev.parent = parent;
407a1a98689SHans de Goede 	priv->dev.release = drm_privacy_screen_device_release;
408a1a98689SHans de Goede 	dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent));
40930598d92SRajat Jain 	priv->drvdata = data;
410a1a98689SHans de Goede 	priv->ops = ops;
411a1a98689SHans de Goede 
412a1a98689SHans de Goede 	priv->ops->get_hw_state(priv);
413a1a98689SHans de Goede 
414a1a98689SHans de Goede 	ret = device_register(&priv->dev);
415a1a98689SHans de Goede 	if (ret) {
416a1a98689SHans de Goede 		put_device(&priv->dev);
417a1a98689SHans de Goede 		return ERR_PTR(ret);
418a1a98689SHans de Goede 	}
419a1a98689SHans de Goede 
420a1a98689SHans de Goede 	mutex_lock(&drm_privacy_screen_devs_lock);
421a1a98689SHans de Goede 	list_add(&priv->list, &drm_privacy_screen_devs);
422a1a98689SHans de Goede 	mutex_unlock(&drm_privacy_screen_devs_lock);
423a1a98689SHans de Goede 
424a1a98689SHans de Goede 	return priv;
425a1a98689SHans de Goede }
426a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_register);
427a1a98689SHans de Goede 
428a1a98689SHans de Goede /**
429a1a98689SHans de Goede  * drm_privacy_screen_unregister - unregister privacy-screen
430a1a98689SHans de Goede  * @priv: privacy-screen to unregister
431a1a98689SHans de Goede  *
432a1a98689SHans de Goede  * Unregister a privacy-screen registered with drm_privacy_screen_register().
433a1a98689SHans de Goede  * May be called with a NULL or ERR_PTR, in which case it is a no-op.
434a1a98689SHans de Goede  */
drm_privacy_screen_unregister(struct drm_privacy_screen * priv)435a1a98689SHans de Goede void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
436a1a98689SHans de Goede {
437a1a98689SHans de Goede 	if (IS_ERR_OR_NULL(priv))
438a1a98689SHans de Goede 		return;
439a1a98689SHans de Goede 
440a1a98689SHans de Goede 	mutex_lock(&drm_privacy_screen_devs_lock);
441a1a98689SHans de Goede 	list_del(&priv->list);
442a1a98689SHans de Goede 	mutex_unlock(&drm_privacy_screen_devs_lock);
443a1a98689SHans de Goede 
444a1a98689SHans de Goede 	mutex_lock(&priv->lock);
44530598d92SRajat Jain 	priv->drvdata = NULL;
446a1a98689SHans de Goede 	priv->ops = NULL;
447a1a98689SHans de Goede 	mutex_unlock(&priv->lock);
448a1a98689SHans de Goede 
449a1a98689SHans de Goede 	device_unregister(&priv->dev);
450a1a98689SHans de Goede }
451a1a98689SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_unregister);
4528a12b170SHans de Goede 
4538a12b170SHans de Goede /**
4548a12b170SHans de Goede  * drm_privacy_screen_call_notifier_chain - notify consumers of state change
4558a12b170SHans de Goede  * @priv: Privacy screen to register the notifier with
4568a12b170SHans de Goede  *
4578a12b170SHans de Goede  * A privacy-screen provider driver can call this functions upon external
4588a12b170SHans de Goede  * changes to the privacy-screen state. E.g. the state may be changed by the
4598a12b170SHans de Goede  * hardware itself in response to a hotkey press.
4608a12b170SHans de Goede  * This function must be called without holding the privacy-screen lock.
4618a12b170SHans de Goede  * the driver must update sw_state and hw_state to reflect the new state before
4628a12b170SHans de Goede  * calling this function.
4638a12b170SHans de Goede  * The expected behavior from the driver upon receiving an external state
4648a12b170SHans de Goede  * change event is: 1. Take the lock; 2. Update sw_state and hw_state;
4658a12b170SHans de Goede  * 3. Release the lock. 4. Call drm_privacy_screen_call_notifier_chain().
4668a12b170SHans de Goede  */
drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen * priv)4678a12b170SHans de Goede void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv)
4688a12b170SHans de Goede {
4698a12b170SHans de Goede 	blocking_notifier_call_chain(&priv->notifier_head, 0, priv);
4708a12b170SHans de Goede }
4718a12b170SHans de Goede EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain);
472