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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 * 383 * Create and register a privacy-screen. 384 * 385 * Return: 386 * * A pointer to the created privacy-screen on success. 387 * * An ERR_PTR(errno) on failure. 388 */ 389 struct drm_privacy_screen *drm_privacy_screen_register( 390 struct device *parent, const struct drm_privacy_screen_ops *ops, 391 void *data) 392 { 393 struct drm_privacy_screen *priv; 394 int ret; 395 396 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 397 if (!priv) 398 return ERR_PTR(-ENOMEM); 399 400 mutex_init(&priv->lock); 401 BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head); 402 403 priv->dev.class = drm_class; 404 priv->dev.type = &drm_privacy_screen_type; 405 priv->dev.parent = parent; 406 priv->dev.release = drm_privacy_screen_device_release; 407 dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); 408 priv->drvdata = data; 409 priv->ops = ops; 410 411 priv->ops->get_hw_state(priv); 412 413 ret = device_register(&priv->dev); 414 if (ret) { 415 put_device(&priv->dev); 416 return ERR_PTR(ret); 417 } 418 419 mutex_lock(&drm_privacy_screen_devs_lock); 420 list_add(&priv->list, &drm_privacy_screen_devs); 421 mutex_unlock(&drm_privacy_screen_devs_lock); 422 423 return priv; 424 } 425 EXPORT_SYMBOL(drm_privacy_screen_register); 426 427 /** 428 * drm_privacy_screen_unregister - unregister privacy-screen 429 * @priv: privacy-screen to unregister 430 * 431 * Unregister a privacy-screen registered with drm_privacy_screen_register(). 432 * May be called with a NULL or ERR_PTR, in which case it is a no-op. 433 */ 434 void drm_privacy_screen_unregister(struct drm_privacy_screen *priv) 435 { 436 if (IS_ERR_OR_NULL(priv)) 437 return; 438 439 mutex_lock(&drm_privacy_screen_devs_lock); 440 list_del(&priv->list); 441 mutex_unlock(&drm_privacy_screen_devs_lock); 442 443 mutex_lock(&priv->lock); 444 priv->drvdata = NULL; 445 priv->ops = NULL; 446 mutex_unlock(&priv->lock); 447 448 device_unregister(&priv->dev); 449 } 450 EXPORT_SYMBOL(drm_privacy_screen_unregister); 451 452 /** 453 * drm_privacy_screen_call_notifier_chain - notify consumers of state change 454 * @priv: Privacy screen to register the notifier with 455 * 456 * A privacy-screen provider driver can call this functions upon external 457 * changes to the privacy-screen state. E.g. the state may be changed by the 458 * hardware itself in response to a hotkey press. 459 * This function must be called without holding the privacy-screen lock. 460 * the driver must update sw_state and hw_state to reflect the new state before 461 * calling this function. 462 * The expected behavior from the driver upon receiving an external state 463 * change event is: 1. Take the lock; 2. Update sw_state and hw_state; 464 * 3. Release the lock. 4. Call drm_privacy_screen_call_notifier_chain(). 465 */ 466 void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv) 467 { 468 blocking_notifier_call_chain(&priv->notifier_head, 0, priv); 469 } 470 EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain); 471