0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/device.h>
0010 #include <linux/kernel.h>
0011 #include <linux/list.h>
0012 #include <linux/module.h>
0013 #include <linux/mutex.h>
0014 #include <linux/slab.h>
0015 #include <drm/drm_privacy_screen_machine.h>
0016 #include <drm/drm_privacy_screen_consumer.h>
0017 #include <drm/drm_privacy_screen_driver.h>
0018 #include "drm_internal.h"
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #define to_drm_privacy_screen(dev) \
0034 container_of(dev, struct drm_privacy_screen, dev)
0035
0036 static DEFINE_MUTEX(drm_privacy_screen_lookup_lock);
0037 static LIST_HEAD(drm_privacy_screen_lookup_list);
0038
0039 static DEFINE_MUTEX(drm_privacy_screen_devs_lock);
0040 static LIST_HEAD(drm_privacy_screen_devs);
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 void drm_privacy_screen_lookup_add(struct drm_privacy_screen_lookup *lookup)
0056 {
0057 mutex_lock(&drm_privacy_screen_lookup_lock);
0058 list_add(&lookup->list, &drm_privacy_screen_lookup_list);
0059 mutex_unlock(&drm_privacy_screen_lookup_lock);
0060 }
0061 EXPORT_SYMBOL(drm_privacy_screen_lookup_add);
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 void drm_privacy_screen_lookup_remove(struct drm_privacy_screen_lookup *lookup)
0072 {
0073 mutex_lock(&drm_privacy_screen_lookup_lock);
0074 list_del(&lookup->list);
0075 mutex_unlock(&drm_privacy_screen_lookup_lock);
0076 }
0077 EXPORT_SYMBOL(drm_privacy_screen_lookup_remove);
0078
0079
0080
0081 static struct drm_privacy_screen *drm_privacy_screen_get_by_name(
0082 const char *name)
0083 {
0084 struct drm_privacy_screen *priv;
0085 struct device *dev = NULL;
0086
0087 mutex_lock(&drm_privacy_screen_devs_lock);
0088
0089 list_for_each_entry(priv, &drm_privacy_screen_devs, list) {
0090 if (strcmp(dev_name(&priv->dev), name) == 0) {
0091 dev = get_device(&priv->dev);
0092 break;
0093 }
0094 }
0095
0096 mutex_unlock(&drm_privacy_screen_devs_lock);
0097
0098 return dev ? to_drm_privacy_screen(dev) : NULL;
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 struct drm_privacy_screen *drm_privacy_screen_get(struct device *dev,
0116 const char *con_id)
0117 {
0118 const char *dev_id = dev ? dev_name(dev) : NULL;
0119 struct drm_privacy_screen_lookup *l;
0120 struct drm_privacy_screen *priv;
0121 const char *provider = NULL;
0122 int match, best = -1;
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 mutex_lock(&drm_privacy_screen_lookup_lock);
0141
0142 list_for_each_entry(l, &drm_privacy_screen_lookup_list, list) {
0143 match = 0;
0144
0145 if (l->dev_id) {
0146 if (!dev_id || strcmp(l->dev_id, dev_id))
0147 continue;
0148
0149 match += 2;
0150 }
0151
0152 if (l->con_id) {
0153 if (!con_id || strcmp(l->con_id, con_id))
0154 continue;
0155
0156 match += 1;
0157 }
0158
0159 if (match > best) {
0160 provider = l->provider;
0161 best = match;
0162 }
0163 }
0164
0165 mutex_unlock(&drm_privacy_screen_lookup_lock);
0166
0167 if (!provider)
0168 return ERR_PTR(-ENODEV);
0169
0170 priv = drm_privacy_screen_get_by_name(provider);
0171 if (!priv)
0172 return ERR_PTR(-EPROBE_DEFER);
0173
0174 return priv;
0175 }
0176 EXPORT_SYMBOL(drm_privacy_screen_get);
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 void drm_privacy_screen_put(struct drm_privacy_screen *priv)
0187 {
0188 if (IS_ERR_OR_NULL(priv))
0189 return;
0190
0191 put_device(&priv->dev);
0192 }
0193 EXPORT_SYMBOL(drm_privacy_screen_put);
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208 int drm_privacy_screen_set_sw_state(struct drm_privacy_screen *priv,
0209 enum drm_privacy_screen_status sw_state)
0210 {
0211 int ret = 0;
0212
0213 mutex_lock(&priv->lock);
0214
0215 if (!priv->ops) {
0216 ret = -ENODEV;
0217 goto out;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227 if (priv->hw_state >= PRIVACY_SCREEN_DISABLED_LOCKED ||
0228 priv->hw_state == sw_state) {
0229 priv->sw_state = sw_state;
0230 goto out;
0231 }
0232
0233 ret = priv->ops->set_sw_state(priv, sw_state);
0234 out:
0235 mutex_unlock(&priv->lock);
0236 return ret;
0237 }
0238 EXPORT_SYMBOL(drm_privacy_screen_set_sw_state);
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 void drm_privacy_screen_get_state(struct drm_privacy_screen *priv,
0250 enum drm_privacy_screen_status *sw_state_ret,
0251 enum drm_privacy_screen_status *hw_state_ret)
0252 {
0253 mutex_lock(&priv->lock);
0254 *sw_state_ret = priv->sw_state;
0255 *hw_state_ret = priv->hw_state;
0256 mutex_unlock(&priv->lock);
0257 }
0258 EXPORT_SYMBOL(drm_privacy_screen_get_state);
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280 int drm_privacy_screen_register_notifier(struct drm_privacy_screen *priv,
0281 struct notifier_block *nb)
0282 {
0283 return blocking_notifier_chain_register(&priv->notifier_head, nb);
0284 }
0285 EXPORT_SYMBOL(drm_privacy_screen_register_notifier);
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 int drm_privacy_screen_unregister_notifier(struct drm_privacy_screen *priv,
0297 struct notifier_block *nb)
0298 {
0299 return blocking_notifier_chain_unregister(&priv->notifier_head, nb);
0300 }
0301 EXPORT_SYMBOL(drm_privacy_screen_unregister_notifier);
0302
0303
0304
0305 static ssize_t sw_state_show(struct device *dev,
0306 struct device_attribute *attr, char *buf)
0307 {
0308 struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0309 const char * const sw_state_names[] = {
0310 "Disabled",
0311 "Enabled",
0312 };
0313 ssize_t ret;
0314
0315 mutex_lock(&priv->lock);
0316
0317 if (!priv->ops)
0318 ret = -ENODEV;
0319 else if (WARN_ON(priv->sw_state >= ARRAY_SIZE(sw_state_names)))
0320 ret = -ENXIO;
0321 else
0322 ret = sprintf(buf, "%s\n", sw_state_names[priv->sw_state]);
0323
0324 mutex_unlock(&priv->lock);
0325 return ret;
0326 }
0327
0328
0329
0330
0331 static DEVICE_ATTR_RO(sw_state);
0332
0333 static ssize_t hw_state_show(struct device *dev,
0334 struct device_attribute *attr, char *buf)
0335 {
0336 struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0337 const char * const hw_state_names[] = {
0338 "Disabled",
0339 "Enabled",
0340 "Disabled, locked",
0341 "Enabled, locked",
0342 };
0343 ssize_t ret;
0344
0345 mutex_lock(&priv->lock);
0346
0347 if (!priv->ops)
0348 ret = -ENODEV;
0349 else if (WARN_ON(priv->hw_state >= ARRAY_SIZE(hw_state_names)))
0350 ret = -ENXIO;
0351 else
0352 ret = sprintf(buf, "%s\n", hw_state_names[priv->hw_state]);
0353
0354 mutex_unlock(&priv->lock);
0355 return ret;
0356 }
0357 static DEVICE_ATTR_RO(hw_state);
0358
0359 static struct attribute *drm_privacy_screen_attrs[] = {
0360 &dev_attr_sw_state.attr,
0361 &dev_attr_hw_state.attr,
0362 NULL
0363 };
0364 ATTRIBUTE_GROUPS(drm_privacy_screen);
0365
0366 static struct device_type drm_privacy_screen_type = {
0367 .name = "privacy_screen",
0368 .groups = drm_privacy_screen_groups,
0369 };
0370
0371 static void drm_privacy_screen_device_release(struct device *dev)
0372 {
0373 struct drm_privacy_screen *priv = to_drm_privacy_screen(dev);
0374
0375 kfree(priv);
0376 }
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 struct drm_privacy_screen *drm_privacy_screen_register(
0391 struct device *parent, const struct drm_privacy_screen_ops *ops,
0392 void *data)
0393 {
0394 struct drm_privacy_screen *priv;
0395 int ret;
0396
0397 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0398 if (!priv)
0399 return ERR_PTR(-ENOMEM);
0400
0401 mutex_init(&priv->lock);
0402 BLOCKING_INIT_NOTIFIER_HEAD(&priv->notifier_head);
0403
0404 priv->dev.class = drm_class;
0405 priv->dev.type = &drm_privacy_screen_type;
0406 priv->dev.parent = parent;
0407 priv->dev.release = drm_privacy_screen_device_release;
0408 dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent));
0409 priv->drvdata = data;
0410 priv->ops = ops;
0411
0412 priv->ops->get_hw_state(priv);
0413
0414 ret = device_register(&priv->dev);
0415 if (ret) {
0416 put_device(&priv->dev);
0417 return ERR_PTR(ret);
0418 }
0419
0420 mutex_lock(&drm_privacy_screen_devs_lock);
0421 list_add(&priv->list, &drm_privacy_screen_devs);
0422 mutex_unlock(&drm_privacy_screen_devs_lock);
0423
0424 return priv;
0425 }
0426 EXPORT_SYMBOL(drm_privacy_screen_register);
0427
0428
0429
0430
0431
0432
0433
0434
0435 void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
0436 {
0437 if (IS_ERR_OR_NULL(priv))
0438 return;
0439
0440 mutex_lock(&drm_privacy_screen_devs_lock);
0441 list_del(&priv->list);
0442 mutex_unlock(&drm_privacy_screen_devs_lock);
0443
0444 mutex_lock(&priv->lock);
0445 priv->drvdata = NULL;
0446 priv->ops = NULL;
0447 mutex_unlock(&priv->lock);
0448
0449 device_unregister(&priv->dev);
0450 }
0451 EXPORT_SYMBOL(drm_privacy_screen_unregister);
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467 void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv)
0468 {
0469 blocking_notifier_call_chain(&priv->notifier_head, 0, priv);
0470 }
0471 EXPORT_SYMBOL(drm_privacy_screen_call_notifier_chain);