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