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