Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
drm_sysfs.c
Go to the documentation of this file.
1 
2 /*
3  * drm_sysfs.c - Modifications to drm_sysfs_class.c to support
4  * extra sysfs attribute from DRM. Normal drm_sysfs_class
5  * does not allow adding attributes.
6  *
7  * Copyright (c) 2004 Jon Smirl <[email protected]>
8  * Copyright (c) 2003-2004 Greg Kroah-Hartman <[email protected]>
9  * Copyright (c) 2003-2004 IBM Corp.
10  *
11  * This file is released under the GPLv2
12  *
13  */
14 
15 #include <linux/device.h>
16 #include <linux/kdev_t.h>
17 #include <linux/gfp.h>
18 #include <linux/err.h>
19 #include <linux/export.h>
20 
21 #include <drm/drm_sysfs.h>
22 #include <drm/drm_core.h>
23 #include <drm/drmP.h>
24 
25 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
26 #define to_drm_connector(d) container_of(d, struct drm_connector, kdev)
27 
28 static struct device_type drm_sysfs_device_minor = {
29  .name = "drm_minor"
30 };
31 
40 static int drm_class_suspend(struct device *dev, pm_message_t state)
41 {
42  if (dev->type == &drm_sysfs_device_minor) {
43  struct drm_minor *drm_minor = to_drm_minor(dev);
44  struct drm_device *drm_dev = drm_minor->dev;
45 
46  if (drm_minor->type == DRM_MINOR_LEGACY &&
47  !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
48  drm_dev->driver->suspend)
49  return drm_dev->driver->suspend(drm_dev, state);
50  }
51  return 0;
52 }
53 
61 static int drm_class_resume(struct device *dev)
62 {
63  if (dev->type == &drm_sysfs_device_minor) {
64  struct drm_minor *drm_minor = to_drm_minor(dev);
65  struct drm_device *drm_dev = drm_minor->dev;
66 
67  if (drm_minor->type == DRM_MINOR_LEGACY &&
68  !drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
69  drm_dev->driver->resume)
70  return drm_dev->driver->resume(drm_dev);
71  }
72  return 0;
73 }
74 
75 static char *drm_devnode(struct device *dev, umode_t *mode)
76 {
77  return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
78 }
79 
81  CORE_NAME " "
85  CORE_DATE);
86 
98 struct class *drm_sysfs_create(struct module *owner, char *name)
99 {
100  struct class *class;
101  int err;
102 
103  class = class_create(owner, name);
104  if (IS_ERR(class)) {
105  err = PTR_ERR(class);
106  goto err_out;
107  }
108 
109  class->suspend = drm_class_suspend;
110  class->resume = drm_class_resume;
111 
112  err = class_create_file(class, &class_attr_version.attr);
113  if (err)
114  goto err_out_class;
115 
116  class->devnode = drm_devnode;
117 
118  return class;
119 
120 err_out_class:
121  class_destroy(class);
122 err_out:
123  return ERR_PTR(err);
124 }
125 
132 {
133  if ((drm_class == NULL) || (IS_ERR(drm_class)))
134  return;
135  class_remove_file(drm_class, &class_attr_version.attr);
137  drm_class = NULL;
138 }
139 
148 static void drm_sysfs_device_release(struct device *dev)
149 {
150  memset(dev, 0, sizeof(struct device));
151  return;
152 }
153 
154 /*
155  * Connector properties
156  */
157 static ssize_t status_show(struct device *device,
158  struct device_attribute *attr,
159  char *buf)
160 {
161  struct drm_connector *connector = to_drm_connector(device);
163  int ret;
164 
165  ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
166  if (ret)
167  return ret;
168 
169  status = connector->funcs->detect(connector, true);
170  mutex_unlock(&connector->dev->mode_config.mutex);
171 
172  return snprintf(buf, PAGE_SIZE, "%s\n",
174 }
175 
176 static ssize_t dpms_show(struct device *device,
177  struct device_attribute *attr,
178  char *buf)
179 {
180  struct drm_connector *connector = to_drm_connector(device);
181  struct drm_device *dev = connector->dev;
182  uint64_t dpms_status;
183  int ret;
184 
185  ret = drm_connector_property_get_value(connector,
186  dev->mode_config.dpms_property,
187  &dpms_status);
188  if (ret)
189  return 0;
190 
191  return snprintf(buf, PAGE_SIZE, "%s\n",
192  drm_get_dpms_name((int)dpms_status));
193 }
194 
195 static ssize_t enabled_show(struct device *device,
196  struct device_attribute *attr,
197  char *buf)
198 {
199  struct drm_connector *connector = to_drm_connector(device);
200 
201  return snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" :
202  "disabled");
203 }
204 
205 static ssize_t edid_show(struct file *filp, struct kobject *kobj,
206  struct bin_attribute *attr, char *buf, loff_t off,
207  size_t count)
208 {
209  struct device *connector_dev = container_of(kobj, struct device, kobj);
210  struct drm_connector *connector = to_drm_connector(connector_dev);
211  unsigned char *edid;
212  size_t size;
213 
214  if (!connector->edid_blob_ptr)
215  return 0;
216 
217  edid = connector->edid_blob_ptr->data;
218  size = connector->edid_blob_ptr->length;
219  if (!edid)
220  return 0;
221 
222  if (off >= size)
223  return 0;
224 
225  if (off + count > size)
226  count = size - off;
227  memcpy(buf, edid + off, count);
228 
229  return count;
230 }
231 
232 static ssize_t modes_show(struct device *device,
233  struct device_attribute *attr,
234  char *buf)
235 {
236  struct drm_connector *connector = to_drm_connector(device);
237  struct drm_display_mode *mode;
238  int written = 0;
239 
240  list_for_each_entry(mode, &connector->modes, head) {
241  written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
242  mode->name);
243  }
244 
245  return written;
246 }
247 
248 static ssize_t subconnector_show(struct device *device,
249  struct device_attribute *attr,
250  char *buf)
251 {
252  struct drm_connector *connector = to_drm_connector(device);
253  struct drm_device *dev = connector->dev;
254  struct drm_property *prop = NULL;
255  uint64_t subconnector;
256  int is_tv = 0;
257  int ret;
258 
259  switch (connector->connector_type) {
261  prop = dev->mode_config.dvi_i_subconnector_property;
262  break;
267  prop = dev->mode_config.tv_subconnector_property;
268  is_tv = 1;
269  break;
270  default:
271  DRM_ERROR("Wrong connector type for this property\n");
272  return 0;
273  }
274 
275  if (!prop) {
276  DRM_ERROR("Unable to find subconnector property\n");
277  return 0;
278  }
279 
280  ret = drm_connector_property_get_value(connector, prop, &subconnector);
281  if (ret)
282  return 0;
283 
284  return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
285  drm_get_tv_subconnector_name((int)subconnector) :
286  drm_get_dvi_i_subconnector_name((int)subconnector));
287 }
288 
289 static ssize_t select_subconnector_show(struct device *device,
290  struct device_attribute *attr,
291  char *buf)
292 {
293  struct drm_connector *connector = to_drm_connector(device);
294  struct drm_device *dev = connector->dev;
295  struct drm_property *prop = NULL;
296  uint64_t subconnector;
297  int is_tv = 0;
298  int ret;
299 
300  switch (connector->connector_type) {
302  prop = dev->mode_config.dvi_i_select_subconnector_property;
303  break;
308  prop = dev->mode_config.tv_select_subconnector_property;
309  is_tv = 1;
310  break;
311  default:
312  DRM_ERROR("Wrong connector type for this property\n");
313  return 0;
314  }
315 
316  if (!prop) {
317  DRM_ERROR("Unable to find select subconnector property\n");
318  return 0;
319  }
320 
321  ret = drm_connector_property_get_value(connector, prop, &subconnector);
322  if (ret)
323  return 0;
324 
325  return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
326  drm_get_tv_select_name((int)subconnector) :
327  drm_get_dvi_i_select_name((int)subconnector));
328 }
329 
330 static struct device_attribute connector_attrs[] = {
331  __ATTR_RO(status),
333  __ATTR_RO(dpms),
334  __ATTR_RO(modes),
335 };
336 
337 /* These attributes are for both DVI-I connectors and all types of tv-out. */
338 static struct device_attribute connector_attrs_opt1[] = {
339  __ATTR_RO(subconnector),
340  __ATTR_RO(select_subconnector),
341 };
342 
343 static struct bin_attribute edid_attr = {
344  .attr.name = "edid",
345  .attr.mode = 0444,
346  .size = 0,
347  .read = edid_show,
348 };
349 
365 {
366  struct drm_device *dev = connector->dev;
367  int attr_cnt = 0;
368  int opt_cnt = 0;
369  int i;
370  int ret;
371 
372  /* We shouldn't get called more than once for the same connector */
373  BUG_ON(device_is_registered(&connector->kdev));
374 
375  connector->kdev.parent = &dev->primary->kdev;
376  connector->kdev.class = drm_class;
377  connector->kdev.release = drm_sysfs_device_release;
378 
379  DRM_DEBUG("adding \"%s\" to sysfs\n",
380  drm_get_connector_name(connector));
381 
382  dev_set_name(&connector->kdev, "card%d-%s",
383  dev->primary->index, drm_get_connector_name(connector));
384  ret = device_register(&connector->kdev);
385 
386  if (ret) {
387  DRM_ERROR("failed to register connector device: %d\n", ret);
388  goto out;
389  }
390 
391  /* Standard attributes */
392 
393  for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) {
394  ret = device_create_file(&connector->kdev, &connector_attrs[attr_cnt]);
395  if (ret)
396  goto err_out_files;
397  }
398 
399  /* Optional attributes */
400  /*
401  * In the long run it maybe a good idea to make one set of
402  * optionals per connector type.
403  */
404  switch (connector->connector_type) {
410  for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) {
411  ret = device_create_file(&connector->kdev, &connector_attrs_opt1[opt_cnt]);
412  if (ret)
413  goto err_out_files;
414  }
415  break;
416  default:
417  break;
418  }
419 
420  ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr);
421  if (ret)
422  goto err_out_files;
423 
424  /* Let userspace know we have a new connector */
426 
427  return 0;
428 
429 err_out_files:
430  for (i = 0; i < opt_cnt; i++)
431  device_remove_file(&connector->kdev, &connector_attrs_opt1[i]);
432  for (i = 0; i < attr_cnt; i++)
433  device_remove_file(&connector->kdev, &connector_attrs[i]);
434  device_unregister(&connector->kdev);
435 
436 out:
437  return ret;
438 }
440 
455 {
456  int i;
457 
458  if (!connector->kdev.parent)
459  return;
460  DRM_DEBUG("removing \"%s\" from sysfs\n",
461  drm_get_connector_name(connector));
462 
463  for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
464  device_remove_file(&connector->kdev, &connector_attrs[i]);
465  sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
466  device_unregister(&connector->kdev);
467  connector->kdev.parent = NULL;
468 }
470 
480 {
481  char *event_string = "HOTPLUG=1";
482  char *envp[] = { event_string, NULL };
483 
484  DRM_DEBUG("generating hotplug event\n");
485 
486  kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
487 }
489 
499 int drm_sysfs_device_add(struct drm_minor *minor)
500 {
501  int err;
502  char *minor_str;
503 
504  minor->kdev.parent = minor->dev->dev;
505 
506  minor->kdev.class = drm_class;
507  minor->kdev.release = drm_sysfs_device_release;
508  minor->kdev.devt = minor->device;
509  minor->kdev.type = &drm_sysfs_device_minor;
510  if (minor->type == DRM_MINOR_CONTROL)
511  minor_str = "controlD%d";
512  else if (minor->type == DRM_MINOR_RENDER)
513  minor_str = "renderD%d";
514  else
515  minor_str = "card%d";
516 
517  dev_set_name(&minor->kdev, minor_str, minor->index);
518 
519  err = device_register(&minor->kdev);
520  if (err) {
521  DRM_ERROR("device add failed: %d\n", err);
522  goto err_out;
523  }
524 
525  return 0;
526 
527 err_out:
528  return err;
529 }
530 
538 void drm_sysfs_device_remove(struct drm_minor *minor)
539 {
540  if (minor->kdev.parent)
541  device_unregister(&minor->kdev);
542  minor->kdev.parent = NULL;
543 }
544 
545 
556 int drm_class_device_register(struct device *dev)
557 {
558  if (!drm_class || IS_ERR(drm_class))
559  return -ENOENT;
560 
561  dev->class = drm_class;
562  return device_register(dev);
563 }
565 
566 void drm_class_device_unregister(struct device *dev)
567 {
568  return device_unregister(dev);
569 }