drm: Add ddc link in sysfs created by drm_connector
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_sysfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 /*
4  * drm_sysfs.c - Modifications to drm_sysfs_class.c to support
5  *               extra sysfs attribute from DRM. Normal drm_sysfs_class
6  *               does not allow adding attributes.
7  *
8  * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com>
9  * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
10  * Copyright (c) 2003-2004 IBM Corp.
11  */
12
13 #include <linux/device.h>
14 #include <linux/err.h>
15 #include <linux/export.h>
16 #include <linux/gfp.h>
17 #include <linux/i2c.h>
18 #include <linux/kdev_t.h>
19 #include <linux/slab.h>
20
21 #include <drm/drm_connector.h>
22 #include <drm/drm_device.h>
23 #include <drm/drm_file.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_print.h>
26 #include <drm/drm_property.h>
27 #include <drm/drm_sysfs.h>
28
29 #include "drm_internal.h"
30
31 #define to_drm_minor(d) dev_get_drvdata(d)
32 #define to_drm_connector(d) dev_get_drvdata(d)
33
34 /**
35  * DOC: overview
36  *
37  * DRM provides very little additional support to drivers for sysfs
38  * interactions, beyond just all the standard stuff. Drivers who want to expose
39  * additional sysfs properties and property groups can attach them at either
40  * &drm_device.dev or &drm_connector.kdev.
41  *
42  * Registration is automatically handled when calling drm_dev_register(), or
43  * drm_connector_register() in case of hot-plugged connectors. Unregistration is
44  * also automatically handled by drm_dev_unregister() and
45  * drm_connector_unregister().
46  */
47
48 static struct device_type drm_sysfs_device_minor = {
49         .name = "drm_minor"
50 };
51
52 struct class *drm_class;
53
54 static char *drm_devnode(struct device *dev, umode_t *mode)
55 {
56         return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
57 }
58
59 static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810");
60
61 /**
62  * drm_sysfs_init - initialize sysfs helpers
63  *
64  * This is used to create the DRM class, which is the implicit parent of any
65  * other top-level DRM sysfs objects.
66  *
67  * You must call drm_sysfs_destroy() to release the allocated resources.
68  *
69  * Return: 0 on success, negative error code on failure.
70  */
71 int drm_sysfs_init(void)
72 {
73         int err;
74
75         drm_class = class_create(THIS_MODULE, "drm");
76         if (IS_ERR(drm_class))
77                 return PTR_ERR(drm_class);
78
79         err = class_create_file(drm_class, &class_attr_version.attr);
80         if (err) {
81                 class_destroy(drm_class);
82                 drm_class = NULL;
83                 return err;
84         }
85
86         drm_class->devnode = drm_devnode;
87         drm_setup_hdcp_srm(drm_class);
88         return 0;
89 }
90
91 /**
92  * drm_sysfs_destroy - destroys DRM class
93  *
94  * Destroy the DRM device class.
95  */
96 void drm_sysfs_destroy(void)
97 {
98         if (IS_ERR_OR_NULL(drm_class))
99                 return;
100         drm_teardown_hdcp_srm(drm_class);
101         class_remove_file(drm_class, &class_attr_version.attr);
102         class_destroy(drm_class);
103         drm_class = NULL;
104 }
105
106 /*
107  * Connector properties
108  */
109 static ssize_t status_store(struct device *device,
110                            struct device_attribute *attr,
111                            const char *buf, size_t count)
112 {
113         struct drm_connector *connector = to_drm_connector(device);
114         struct drm_device *dev = connector->dev;
115         enum drm_connector_force old_force;
116         int ret;
117
118         ret = mutex_lock_interruptible(&dev->mode_config.mutex);
119         if (ret)
120                 return ret;
121
122         old_force = connector->force;
123
124         if (sysfs_streq(buf, "detect"))
125                 connector->force = 0;
126         else if (sysfs_streq(buf, "on"))
127                 connector->force = DRM_FORCE_ON;
128         else if (sysfs_streq(buf, "on-digital"))
129                 connector->force = DRM_FORCE_ON_DIGITAL;
130         else if (sysfs_streq(buf, "off"))
131                 connector->force = DRM_FORCE_OFF;
132         else
133                 ret = -EINVAL;
134
135         if (old_force != connector->force || !connector->force) {
136                 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
137                               connector->base.id,
138                               connector->name,
139                               old_force, connector->force);
140
141                 connector->funcs->fill_modes(connector,
142                                              dev->mode_config.max_width,
143                                              dev->mode_config.max_height);
144         }
145
146         mutex_unlock(&dev->mode_config.mutex);
147
148         return ret ? ret : count;
149 }
150
151 static ssize_t status_show(struct device *device,
152                            struct device_attribute *attr,
153                            char *buf)
154 {
155         struct drm_connector *connector = to_drm_connector(device);
156         enum drm_connector_status status;
157
158         status = READ_ONCE(connector->status);
159
160         return snprintf(buf, PAGE_SIZE, "%s\n",
161                         drm_get_connector_status_name(status));
162 }
163
164 static ssize_t dpms_show(struct device *device,
165                            struct device_attribute *attr,
166                            char *buf)
167 {
168         struct drm_connector *connector = to_drm_connector(device);
169         int dpms;
170
171         dpms = READ_ONCE(connector->dpms);
172
173         return snprintf(buf, PAGE_SIZE, "%s\n",
174                         drm_get_dpms_name(dpms));
175 }
176
177 static ssize_t enabled_show(struct device *device,
178                             struct device_attribute *attr,
179                            char *buf)
180 {
181         struct drm_connector *connector = to_drm_connector(device);
182         bool enabled;
183
184         enabled = READ_ONCE(connector->encoder);
185
186         return snprintf(buf, PAGE_SIZE, enabled ? "enabled\n" : "disabled\n");
187 }
188
189 static ssize_t edid_show(struct file *filp, struct kobject *kobj,
190                          struct bin_attribute *attr, char *buf, loff_t off,
191                          size_t count)
192 {
193         struct device *connector_dev = kobj_to_dev(kobj);
194         struct drm_connector *connector = to_drm_connector(connector_dev);
195         unsigned char *edid;
196         size_t size;
197         ssize_t ret = 0;
198
199         mutex_lock(&connector->dev->mode_config.mutex);
200         if (!connector->edid_blob_ptr)
201                 goto unlock;
202
203         edid = connector->edid_blob_ptr->data;
204         size = connector->edid_blob_ptr->length;
205         if (!edid)
206                 goto unlock;
207
208         if (off >= size)
209                 goto unlock;
210
211         if (off + count > size)
212                 count = size - off;
213         memcpy(buf, edid + off, count);
214
215         ret = count;
216 unlock:
217         mutex_unlock(&connector->dev->mode_config.mutex);
218
219         return ret;
220 }
221
222 static ssize_t modes_show(struct device *device,
223                            struct device_attribute *attr,
224                            char *buf)
225 {
226         struct drm_connector *connector = to_drm_connector(device);
227         struct drm_display_mode *mode;
228         int written = 0;
229
230         mutex_lock(&connector->dev->mode_config.mutex);
231         list_for_each_entry(mode, &connector->modes, head) {
232                 written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
233                                     mode->name);
234         }
235         mutex_unlock(&connector->dev->mode_config.mutex);
236
237         return written;
238 }
239
240 static DEVICE_ATTR_RW(status);
241 static DEVICE_ATTR_RO(enabled);
242 static DEVICE_ATTR_RO(dpms);
243 static DEVICE_ATTR_RO(modes);
244
245 static struct attribute *connector_dev_attrs[] = {
246         &dev_attr_status.attr,
247         &dev_attr_enabled.attr,
248         &dev_attr_dpms.attr,
249         &dev_attr_modes.attr,
250         NULL
251 };
252
253 static struct bin_attribute edid_attr = {
254         .attr.name = "edid",
255         .attr.mode = 0444,
256         .size = 0,
257         .read = edid_show,
258 };
259
260 static struct bin_attribute *connector_bin_attrs[] = {
261         &edid_attr,
262         NULL
263 };
264
265 static const struct attribute_group connector_dev_group = {
266         .attrs = connector_dev_attrs,
267         .bin_attrs = connector_bin_attrs,
268 };
269
270 static const struct attribute_group *connector_dev_groups[] = {
271         &connector_dev_group,
272         NULL
273 };
274
275 int drm_sysfs_connector_add(struct drm_connector *connector)
276 {
277         struct drm_device *dev = connector->dev;
278
279         if (connector->kdev)
280                 return 0;
281
282         connector->kdev =
283                 device_create_with_groups(drm_class, dev->primary->kdev, 0,
284                                           connector, connector_dev_groups,
285                                           "card%d-%s", dev->primary->index,
286                                           connector->name);
287         DRM_DEBUG("adding \"%s\" to sysfs\n",
288                   connector->name);
289
290         if (IS_ERR(connector->kdev)) {
291                 DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
292                 return PTR_ERR(connector->kdev);
293         }
294
295         /* Let userspace know we have a new connector */
296         drm_sysfs_hotplug_event(dev);
297
298         if (connector->ddc)
299                 return sysfs_create_link(&connector->kdev->kobj,
300                                  &connector->ddc->dev.kobj, "ddc");
301         return 0;
302 }
303
304 void drm_sysfs_connector_remove(struct drm_connector *connector)
305 {
306         if (!connector->kdev)
307                 return;
308
309         if (connector->ddc)
310                 sysfs_remove_link(&connector->kdev->kobj, "ddc");
311
312         DRM_DEBUG("removing \"%s\" from sysfs\n",
313                   connector->name);
314
315         device_unregister(connector->kdev);
316         connector->kdev = NULL;
317 }
318
319 void drm_sysfs_lease_event(struct drm_device *dev)
320 {
321         char *event_string = "LEASE=1";
322         char *envp[] = { event_string, NULL };
323
324         DRM_DEBUG("generating lease event\n");
325
326         kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
327 }
328
329 /**
330  * drm_sysfs_hotplug_event - generate a DRM uevent
331  * @dev: DRM device
332  *
333  * Send a uevent for the DRM device specified by @dev.  Currently we only
334  * set HOTPLUG=1 in the uevent environment, but this could be expanded to
335  * deal with other types of events.
336  */
337 void drm_sysfs_hotplug_event(struct drm_device *dev)
338 {
339         char *event_string = "HOTPLUG=1";
340         char *envp[] = { event_string, NULL };
341
342         DRM_DEBUG("generating hotplug event\n");
343
344         kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
345 }
346 EXPORT_SYMBOL(drm_sysfs_hotplug_event);
347
348 static void drm_sysfs_release(struct device *dev)
349 {
350         kfree(dev);
351 }
352
353 struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
354 {
355         const char *minor_str;
356         struct device *kdev;
357         int r;
358
359         if (minor->type == DRM_MINOR_RENDER)
360                 minor_str = "renderD%d";
361         else
362                 minor_str = "card%d";
363
364         kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
365         if (!kdev)
366                 return ERR_PTR(-ENOMEM);
367
368         device_initialize(kdev);
369         kdev->devt = MKDEV(DRM_MAJOR, minor->index);
370         kdev->class = drm_class;
371         kdev->type = &drm_sysfs_device_minor;
372         kdev->parent = minor->dev->dev;
373         kdev->release = drm_sysfs_release;
374         dev_set_drvdata(kdev, minor);
375
376         r = dev_set_name(kdev, minor_str, minor->index);
377         if (r < 0)
378                 goto err_free;
379
380         return kdev;
381
382 err_free:
383         put_device(kdev);
384         return ERR_PTR(r);
385 }
386
387 /**
388  * drm_class_device_register - register new device with the DRM sysfs class
389  * @dev: device to register
390  *
391  * Registers a new &struct device within the DRM sysfs class. Essentially only
392  * used by ttm to have a place for its global settings. Drivers should never use
393  * this.
394  */
395 int drm_class_device_register(struct device *dev)
396 {
397         if (!drm_class || IS_ERR(drm_class))
398                 return -ENOENT;
399
400         dev->class = drm_class;
401         return device_register(dev);
402 }
403 EXPORT_SYMBOL_GPL(drm_class_device_register);
404
405 /**
406  * drm_class_device_unregister - unregister device with the DRM sysfs class
407  * @dev: device to unregister
408  *
409  * Unregisters a &struct device from the DRM sysfs class. Essentially only used
410  * by ttm to have a place for its global settings. Drivers should never use
411  * this.
412  */
413 void drm_class_device_unregister(struct device *dev)
414 {
415         return device_unregister(dev);
416 }
417 EXPORT_SYMBOL_GPL(drm_class_device_unregister);