From: Thomas H. <the...@vm...> - 2009-08-12 08:37:03
|
This code wraps the struct device so that the drm class callbacks can differentiate between different types of drm sysfs devices. It fixes a case where a struct drm_connecor is cast to a struct drm_minor in the drm_sysfs[suspend|resume] code. It also opens up for adding driver-specific device entries to the drm sysfs class, where the struct device need not be embedded within a struct drm_minor. A new include "drm_sysfs.h" is added so that drivers don't need to include the full drmP.h to access this feature. Signed-off-by: Thomas Hellstrom <the...@vm...> --- drivers/gpu/drm/drm_sysfs.c | 134 ++++++++++++++++++++++++++++-------------- include/drm/drmP.h | 3 +- include/drm/drm_crtc.h | 3 +- include/drm/drm_sysfs.h | 37 ++++++++++++ 4 files changed, 130 insertions(+), 47 deletions(-) create mode 100644 include/drm/drm_sysfs.h diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index adc1794..ba54b4c 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -16,11 +16,13 @@ #include <linux/kdev_t.h> #include <linux/err.h> +#include "drm_sysfs.h" #include "drm_core.h" #include "drmP.h" -#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) -#define to_drm_connector(d) container_of(d, struct drm_connector, kdev) +#define to_drm_minor(d) container_of(d, struct drm_minor, dsdev) +#define to_drm_connector(d) container_of(d, struct drm_connector, dsdev) +#define to_dsdev(d) container_of(d, struct drm_sysfs_device, kdev) /** * drm_sysfs_suspend - DRM class suspend hook @@ -32,13 +34,23 @@ */ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) { - struct drm_minor *drm_minor = to_drm_minor(dev); - struct drm_device *drm_dev = drm_minor->dev; - - if (drm_minor->type == DRM_MINOR_LEGACY && - !drm_core_check_feature(drm_dev, DRIVER_MODESET) && - drm_dev->driver->suspend) - return drm_dev->driver->suspend(drm_dev, state); + struct drm_sysfs_device *dsdev = to_dsdev(dev); + + BUG_ON(dsdev->type >= DRM_DEVICE_TYPE_NUM); + switch (dsdev->type) { + case DRM_DEVICE_TYPE_MINOR: + { + struct drm_minor *drm_minor = to_drm_minor(dsdev); + struct drm_device *drm_dev = drm_minor->dev; + + if (drm_minor->type == DRM_MINOR_LEGACY && + !drm_core_check_feature(drm_dev, DRIVER_MODESET) && + drm_dev->driver->suspend) + return drm_dev->driver->suspend(drm_dev, state); + } + default: + break; + } return 0; } @@ -52,16 +64,38 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) */ static int drm_sysfs_resume(struct device *dev) { - struct drm_minor *drm_minor = to_drm_minor(dev); - struct drm_device *drm_dev = drm_minor->dev; + struct drm_sysfs_device *dsdev = to_dsdev(dev); + + BUG_ON(dsdev->type >= DRM_DEVICE_TYPE_NUM); + switch (dsdev->type) { + case DRM_DEVICE_TYPE_MINOR: + { + struct drm_minor *drm_minor = to_drm_minor(dsdev); + struct drm_device *drm_dev = drm_minor->dev; + + if (drm_minor->type == DRM_MINOR_LEGACY && + !drm_core_check_feature(drm_dev, DRIVER_MODESET) && + drm_dev->driver->resume) + return drm_dev->driver->resume(drm_dev); + } + default: + break; + } + return 0; +} - if (drm_minor->type == DRM_MINOR_LEGACY && - !drm_core_check_feature(drm_dev, DRIVER_MODESET) && - drm_dev->driver->resume) - return drm_dev->driver->resume(drm_dev); +int drm_sysfs_device_register(struct drm_sysfs_device *dsdev) +{ + dsdev->kdev.class = drm_class; + return device_register(&dsdev->kdev); +} +EXPORT_SYMBOL(drm_sysfs_device_register); - return 0; +void drm_sysfs_device_unregister(struct drm_sysfs_device *dsdev) +{ + device_unregister(&dsdev->kdev); } +EXPORT_SYMBOL(drm_sysfs_device_unregister); /* Display the version of drm_core. This doesn't work right in current design */ static ssize_t version_show(struct class *dev, char *buf) @@ -150,7 +184,8 @@ static ssize_t status_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); enum drm_connector_status status; status = connector->funcs->detect(connector); @@ -162,7 +197,8 @@ static ssize_t dpms_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); struct drm_device *dev = connector->dev; uint64_t dpms_status; int ret; @@ -181,7 +217,8 @@ static ssize_t enabled_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); return snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" : "disabled"); @@ -191,7 +228,8 @@ static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct device *connector_dev = container_of(kobj, struct device, kobj); - struct drm_connector *connector = to_drm_connector(connector_dev); + struct drm_sysfs_device *dsdev = to_dsdev(connector_dev); + struct drm_connector *connector = to_drm_connector(dsdev); unsigned char *edid; size_t size; @@ -217,7 +255,8 @@ static ssize_t modes_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); struct drm_display_mode *mode; int written = 0; @@ -233,7 +272,8 @@ static ssize_t subconnector_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); struct drm_device *dev = connector->dev; struct drm_property *prop = NULL; uint64_t subconnector; @@ -274,7 +314,8 @@ static ssize_t select_subconnector_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_connector *connector = to_drm_connector(device); + struct drm_sysfs_device *dsdev = to_dsdev(device); + struct drm_connector *connector = to_drm_connector(dsdev); struct drm_device *dev = connector->dev; struct drm_property *prop = NULL; uint64_t subconnector; @@ -351,18 +392,18 @@ int drm_sysfs_connector_add(struct drm_connector *connector) int ret = 0, i, j; /* We shouldn't get called more than once for the same connector */ - BUG_ON(device_is_registered(&connector->kdev)); + BUG_ON(device_is_registered(&connector->dsdev.kdev)); - connector->kdev.parent = &dev->primary->kdev; - connector->kdev.class = drm_class; - connector->kdev.release = drm_sysfs_device_release; + connector->dsdev.type = DRM_DEVICE_TYPE_CONNECTOR; + connector->dsdev.kdev.parent = &dev->primary->dsdev.kdev; + connector->dsdev.kdev.release = drm_sysfs_device_release; DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_connector_name(connector)); - dev_set_name(&connector->kdev, "card%d-%s", + dev_set_name(&connector->dsdev.kdev, "card%d-%s", dev->primary->index, drm_get_connector_name(connector)); - ret = device_register(&connector->kdev); + ret = drm_sysfs_device_register(&connector->dsdev); if (ret) { DRM_ERROR("failed to register connector device: %d\n", ret); @@ -372,7 +413,8 @@ int drm_sysfs_connector_add(struct drm_connector *connector) /* Standard attributes */ for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { - ret = device_create_file(&connector->kdev, &connector_attrs[i]); + ret = device_create_file(&connector->dsdev.kdev, + &connector_attrs[i]); if (ret) goto err_out_files; } @@ -389,7 +431,8 @@ int drm_sysfs_connector_add(struct drm_connector *connector) case DRM_MODE_CONNECTOR_Component: case DRM_MODE_CONNECTOR_TV: for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) { - ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]); + ret = device_create_file(&connector->dsdev.kdev, + &connector_attrs_opt1[i]); if (ret) goto err_out_files; } @@ -398,7 +441,8 @@ int drm_sysfs_connector_add(struct drm_connector *connector) break; } - ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); + ret = sysfs_create_bin_file(&connector->dsdev.kdev.kobj, + &edid_attr); if (ret) goto err_out_files; @@ -410,9 +454,9 @@ int drm_sysfs_connector_add(struct drm_connector *connector) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&connector->kdev, + device_remove_file(&connector->dsdev.kdev, &connector_attrs[i]); - device_unregister(&connector->kdev); + drm_sysfs_device_unregister(&connector->dsdev); out: return ret; @@ -440,9 +484,9 @@ void drm_sysfs_connector_remove(struct drm_connector *connector) drm_get_connector_name(connector)); for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) - device_remove_file(&connector->kdev, &connector_attrs[i]); - sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); - device_unregister(&connector->kdev); + device_remove_file(&connector->dsdev.kdev, &connector_attrs[i]); + sysfs_remove_bin_file(&connector->dsdev.kdev.kobj, &edid_attr); + drm_sysfs_device_unregister(&connector->dsdev); } EXPORT_SYMBOL(drm_sysfs_connector_remove); @@ -461,7 +505,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) DRM_DEBUG("generating hotplug event\n"); - kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); + kobject_uevent_env(&dev->primary->dsdev.kdev.kobj, KOBJ_CHANGE, envp); } EXPORT_SYMBOL(drm_sysfs_hotplug_event); @@ -479,10 +523,10 @@ int drm_sysfs_device_add(struct drm_minor *minor) int err; char *minor_str; - minor->kdev.parent = &minor->dev->pdev->dev; - minor->kdev.class = drm_class; - minor->kdev.release = drm_sysfs_device_release; - minor->kdev.devt = minor->device; + minor->dsdev.type = DRM_DEVICE_TYPE_MINOR; + minor->dsdev.kdev.parent = &minor->dev->pdev->dev; + minor->dsdev.kdev.release = drm_sysfs_device_release; + minor->dsdev.kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) minor_str = "controlD%d"; else if (minor->type == DRM_MINOR_RENDER) @@ -490,9 +534,9 @@ int drm_sysfs_device_add(struct drm_minor *minor) else minor_str = "card%d"; - dev_set_name(&minor->kdev, minor_str, minor->index); + dev_set_name(&minor->dsdev.kdev, minor_str, minor->index); - err = device_register(&minor->kdev); + err = drm_sysfs_device_register(&minor->dsdev); if (err) { DRM_ERROR("device add failed: %d\n", err); goto err_out; @@ -513,5 +557,5 @@ err_out: */ void drm_sysfs_device_remove(struct drm_minor *minor) { - device_unregister(&minor->kdev); + drm_sysfs_device_unregister(&minor->dsdev); } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e0f1c1f..f2e4367 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -84,6 +84,7 @@ struct drm_device; #include "drm_os_linux.h" #include "drm_hashtab.h" #include "drm_mm.h" +#include "drm_sysfs.h" #define DRM_UT_CORE 0x01 #define DRM_UT_DRIVER 0x02 @@ -884,7 +885,7 @@ struct drm_minor { int index; /**< Minor device number */ int type; /**< Control or render */ dev_t device; /**< Device number for mknod */ - struct device kdev; /**< Linux device */ + struct drm_sysfs_device dsdev; /**< Linux device wrapped*/ struct drm_device *dev; struct proc_dir_entry *proc_root; /**< proc directory entry */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5f2cc0c..135b473 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -31,6 +31,7 @@ #include <linux/idr.h> #include <linux/fb.h> +#include "drm_sysfs.h" struct drm_device; struct drm_mode_set; @@ -445,7 +446,7 @@ struct drm_encoder { */ struct drm_connector { struct drm_device *dev; - struct device kdev; + struct drm_sysfs_device dsdev; struct device_attribute *attr; struct list_head head; diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h new file mode 100644 index 0000000..45c6bea --- /dev/null +++ b/include/drm/drm_sysfs.h @@ -0,0 +1,37 @@ +#ifndef _DRM_SYSFS_ +#define _DRM_SYSFS_ +#include <linux/device.h> + +/** + * drm known device types. + * drm doesn't apply the class methods, in particular suspend / resume / pm + * to the DRM_DEVICE_TYPE_OTHER device type. The device should + * register its own method by defining and pointing to a + * linux struct device_type. This way a device can override the class + * methods. + */ + +enum drm_sysfs_device_type { + DRM_DEVICE_TYPE_MINOR, + DRM_DEVICE_TYPE_CONNECTOR, + DRM_DEVICE_TYPE_OTHER, + DRM_DEVICE_TYPE_NUM +}; + +struct drm_sysfs_device { + enum drm_sysfs_device_type type; + struct device kdev; +}; + +/** + * Register a device under the drm sysfs class. + */ + +extern int drm_sysfs_device_register(struct drm_sysfs_device *dsdev); + +/** + * Unregister a device from the drm sysfs class. + */ +extern void drm_sysfs_device_unregister(struct drm_sysfs_device *dsdev); + +#endif -- 1.6.1.3 |