Commit 8a12b170 authored by Hans de Goede's avatar Hans de Goede
Browse files

drm/privacy-screen: Add notifier support (v2)



Add support for privacy-screen consumers to register a notifier to
be notified of external (e.g. done by the hw itself on a hotkey press)
state changes.

Changes in v2:
- Drop WARN_ON(mutex_is_locked(&priv->lock)) check in
  drm_privacy_screen_call_notifier_chain() it may be locked by
  another thread, which would lead to a false-positive triggering
  of the check

Reviewed-by: default avatarEmil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211005202322.700909-5-hdegoede@redhat.com
parent befe5404
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -257,6 +257,49 @@ void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
}
EXPORT_SYMBOL(drm_privacy_screen_get_state);

/**
 * drm_privacy_screen_register_notifier - register a notifier
 * @priv: Privacy screen to register the notifier with
 * @nb: Notifier-block for the notifier to register
 *
 * Register a notifier with the privacy-screen to be notified of changes made
 * to the privacy-screen state from outside of the privacy-screen class.
 * E.g. the state may be changed by the hardware itself in response to a
 * hotkey press.
 *
 * The notifier is called with no locks held. The new hw_state and sw_state
 * can be retrieved using the drm_privacy_screen_get_state() function.
 * A pointer to the drm_privacy_screen's struct is passed as the void *data
 * argument of the notifier_block's notifier_call.
 *
 * The notifier will NOT be called when changes are made through
 * drm_privacy_screen_set_sw_state(). It is only called for external changes.
 *
 * Return: 0 on success, negative error code on failure.
 */
int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv,
					 struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&priv->notifier_head, nb);
}
EXPORT_SYMBOL(drm_privacy_screen_register_notifier);

/**
 * drm_privacy_screen_unregister_notifier - unregister a notifier
 * @priv: Privacy screen to register the notifier with
 * @nb: Notifier-block for the notifier to register
 *
 * Unregister a notifier registered with drm_privacy_screen_register_notifier().
 *
 * Return: 0 on success, negative error code on failure.
 */
int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv,
					   struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&priv->notifier_head, nb);
}
EXPORT_SYMBOL(drm_privacy_screen_unregister_notifier);

/*** drm_privacy_screen_driver.h functions ***/

static ssize_t sw_state_show(struct device *dev,
@@ -354,6 +397,7 @@ struct drm_privacy_screen *drm_privacy_screen_register(
		return ERR_PTR(-ENOMEM);

	mutex_init(&priv->lock);
	BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head);

	priv->dev.class = drm_class;
	priv->dev.type = &drm_privacy_screen_type;
@@ -401,3 +445,23 @@ void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
	device_unregister(&priv->dev);
}
EXPORT_SYMBOL(drm_privacy_screen_unregister);

/**
 * drm_privacy_screen_call_notifier_chain - notify consumers of state change
 * @priv: Privacy screen to register the notifier with
 *
 * A privacy-screen provider driver can call this functions upon external
 * changes to the privacy-screen state. E.g. the state may be changed by the
 * hardware itself in response to a hotkey press.
 * This function must be called without holding the privacy-screen lock.
 * the driver must update sw_state and hw_state to reflect the new state before
 * calling this function.
 * The expected behavior from the driver upon receiving an external state
 * change event is: 1. Take the lock; 2. Update sw_state and hw_state;
 * 3. Release the lock. 4. Call drm_privacy_screen_call_notifier_chain().
 */
void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv)
{
	blocking_notifier_call_chain(&priv->notifier_head, 0, priv);
}
EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain);
+15 −0
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
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);

int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv,
					 struct notifier_block *nb);
int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv,
					   struct notifier_block *nb);
#else
static inline struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
								const char *con_id)
@@ -45,6 +50,16 @@ static inline void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
	*sw_state_ret = PRIVACY_SCREEN_DISABLED;
	*hw_state_ret = PRIVACY_SCREEN_DISABLED;
}
static inline int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv,
						       struct notifier_block *nb)
{
	return -ENODEV;
}
static inline int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv,
							 struct notifier_block *nb)
{
	return -ENODEV;
}
#endif

#endif
+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ struct drm_privacy_screen {
	struct mutex lock;
	/** @list: privacy-screen devices list list-entry. */
	struct list_head list;
	/** @notifier_head: privacy-screen notifier head. */
	struct blocking_notifier_head notifier_head;
	/**
	 * @ops: &struct drm_privacy_screen_ops for this privacy-screen.
	 * This is NULL if the driver has unregistered the privacy-screen.
@@ -77,4 +79,6 @@ 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);

void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv);

#endif