drm_privacy_screen.c 14 KB

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