diff options
Diffstat (limited to 'drivers/gpu/drm/drm_sysfs.c')
| -rw-r--r-- | drivers/gpu/drm/drm_sysfs.c | 184 |
1 files changed, 109 insertions, 75 deletions
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 85da4c40694..369b26278e7 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -16,27 +16,28 @@ #include <linux/kdev_t.h> #include <linux/gfp.h> #include <linux/err.h> +#include <linux/export.h> -#include "drm_sysfs.h" -#include "drm_core.h" -#include "drmP.h" +#include <drm/drm_sysfs.h> +#include <drm/drm_core.h> +#include <drm/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) dev_get_drvdata(d) +#define to_drm_connector(d) dev_get_drvdata(d) static struct device_type drm_sysfs_device_minor = { .name = "drm_minor" }; /** - * drm_class_suspend - DRM class suspend hook + * __drm_class_suspend - internal DRM class suspend routine * @dev: Linux device to suspend * @state: power state to enter * * Just figures out what the actual struct drm_device associated with * @dev is and calls its suspend hook, if present. */ -static int drm_class_suspend(struct device *dev, pm_message_t state) +static int __drm_class_suspend(struct device *dev, pm_message_t state) { if (dev->type == &drm_sysfs_device_minor) { struct drm_minor *drm_minor = to_drm_minor(dev); @@ -51,6 +52,26 @@ static int drm_class_suspend(struct device *dev, pm_message_t state) } /** + * drm_class_suspend - internal DRM class suspend hook. Simply calls + * __drm_class_suspend() with the correct pm state. + * @dev: Linux device to suspend + */ +static int drm_class_suspend(struct device *dev) +{ + return __drm_class_suspend(dev, PMSG_SUSPEND); +} + +/** + * drm_class_freeze - internal DRM class freeze hook. Simply calls + * __drm_class_suspend() with the correct pm state. + * @dev: Linux device to freeze + */ +static int drm_class_freeze(struct device *dev) +{ + return __drm_class_suspend(dev, PMSG_FREEZE); +} + +/** * drm_class_resume - DRM class resume hook * @dev: Linux device to resume * @@ -71,7 +92,13 @@ static int drm_class_resume(struct device *dev) return 0; } -static char *drm_devnode(struct device *dev, mode_t *mode) +static const struct dev_pm_ops drm_class_dev_pm_ops = { + .suspend = drm_class_suspend, + .resume = drm_class_resume, + .freeze = drm_class_freeze, +}; + +static char *drm_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } @@ -105,8 +132,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name) goto err_out; } - class->suspend = drm_class_suspend; - class->resume = drm_class_resume; + class->pm = &drm_class_dev_pm_ops; err = class_create_file(class, &class_attr_version.attr); if (err) @@ -133,20 +159,7 @@ void drm_sysfs_destroy(void) return; class_remove_file(drm_class, &class_attr_version.attr); class_destroy(drm_class); -} - -/** - * drm_sysfs_device_release - do nothing - * @dev: Linux device - * - * Normally, this would free the DRM device associated with @dev, along - * with cleaning up any other stuff. But we do that in the DRM core, so - * this function can just return and hope that the core does its job. - */ -static void drm_sysfs_device_release(struct device *dev) -{ - memset(dev, 0, sizeof(struct device)); - return; + drm_class = NULL; } /* @@ -158,8 +171,15 @@ static ssize_t status_show(struct device *device, { struct drm_connector *connector = to_drm_connector(device); enum drm_connector_status status; + int ret; + + ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex); + if (ret) + return ret; status = connector->funcs->detect(connector, true); + mutex_unlock(&connector->dev->mode_config.mutex); + return snprintf(buf, PAGE_SIZE, "%s\n", drm_get_connector_status_name(status)); } @@ -173,7 +193,7 @@ static ssize_t dpms_show(struct device *device, uint64_t dpms_status; int ret; - ret = drm_connector_property_get_value(connector, + ret = drm_object_property_get_value(&connector->base, dev->mode_config.dpms_property, &dpms_status); if (ret) @@ -268,7 +288,7 @@ static ssize_t subconnector_show(struct device *device, return 0; } - ret = drm_connector_property_get_value(connector, prop, &subconnector); + ret = drm_object_property_get_value(&connector->base, prop, &subconnector); if (ret) return 0; @@ -309,7 +329,7 @@ static ssize_t select_subconnector_show(struct device *device, return 0; } - ret = drm_connector_property_get_value(connector, prop, &subconnector); + ret = drm_object_property_get_value(&connector->base, prop, &subconnector); if (ret) return 0; @@ -339,18 +359,13 @@ static struct bin_attribute edid_attr = { }; /** - * drm_sysfs_connector_add - add an connector to sysfs + * drm_sysfs_connector_add - add a connector to sysfs * @connector: connector to add * - * Create an connector device in sysfs, along with its associated connector + * Create a connector device in sysfs, along with its associated connector * properties (so far, connection status, dpms, mode list & edid) and * generate a hotplug event so userspace knows there's a new connector * available. - * - * Note: - * This routine should only be called *once* for each DRM minor registered. - * A second call for an already registered device will trigger the BUG_ON - * below. */ int drm_sysfs_connector_add(struct drm_connector *connector) { @@ -358,31 +373,27 @@ int drm_sysfs_connector_add(struct drm_connector *connector) int attr_cnt = 0; int opt_cnt = 0; int i; - int ret = 0; - - /* We shouldn't get called more than once for the same connector */ - BUG_ON(device_is_registered(&connector->kdev)); + int ret; - connector->kdev.parent = &dev->primary->kdev; - connector->kdev.class = drm_class; - connector->kdev.release = drm_sysfs_device_release; + if (connector->kdev) + return 0; + connector->kdev = device_create(drm_class, dev->primary->kdev, + 0, connector, "card%d-%s", + dev->primary->index, connector->name); DRM_DEBUG("adding \"%s\" to sysfs\n", - drm_get_connector_name(connector)); - - dev_set_name(&connector->kdev, "card%d-%s", - dev->primary->index, drm_get_connector_name(connector)); - ret = device_register(&connector->kdev); + connector->name); - if (ret) { - DRM_ERROR("failed to register connector device: %d\n", ret); + if (IS_ERR(connector->kdev)) { + DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev)); + ret = PTR_ERR(connector->kdev); goto out; } /* Standard attributes */ for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) { - ret = device_create_file(&connector->kdev, &connector_attrs[attr_cnt]); + ret = device_create_file(connector->kdev, &connector_attrs[attr_cnt]); if (ret) goto err_out_files; } @@ -399,7 +410,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector) case DRM_MODE_CONNECTOR_Component: case DRM_MODE_CONNECTOR_TV: for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) { - ret = device_create_file(&connector->kdev, &connector_attrs_opt1[opt_cnt]); + ret = device_create_file(connector->kdev, &connector_attrs_opt1[opt_cnt]); if (ret) goto err_out_files; } @@ -408,7 +419,7 @@ 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->kdev->kobj, &edid_attr); if (ret) goto err_out_files; @@ -419,10 +430,10 @@ int drm_sysfs_connector_add(struct drm_connector *connector) err_out_files: for (i = 0; i < opt_cnt; i++) - device_remove_file(&connector->kdev, &connector_attrs_opt1[i]); + device_remove_file(connector->kdev, &connector_attrs_opt1[i]); for (i = 0; i < attr_cnt; i++) - device_remove_file(&connector->kdev, &connector_attrs[i]); - device_unregister(&connector->kdev); + device_remove_file(connector->kdev, &connector_attrs[i]); + device_unregister(connector->kdev); out: return ret; @@ -446,13 +457,16 @@ void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; + if (!connector->kdev) + return; DRM_DEBUG("removing \"%s\" from sysfs\n", - drm_get_connector_name(connector)); + connector->name); 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->kdev, &connector_attrs[i]); + sysfs_remove_bin_file(&connector->kdev->kobj, &edid_attr); + device_unregister(connector->kdev); + connector->kdev = NULL; } EXPORT_SYMBOL(drm_sysfs_connector_remove); @@ -471,10 +485,15 @@ 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->kdev->kobj, KOBJ_CHANGE, envp); } EXPORT_SYMBOL(drm_sysfs_hotplug_event); +static void drm_sysfs_release(struct device *dev) +{ + kfree(dev); +} + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver * @dev: DRM device to be added @@ -486,15 +505,9 @@ EXPORT_SYMBOL(drm_sysfs_hotplug_event); */ int drm_sysfs_device_add(struct drm_minor *minor) { - int err; char *minor_str; + int r; - minor->kdev.parent = minor->dev->dev; - - minor->kdev.class = drm_class; - minor->kdev.release = drm_sysfs_device_release; - minor->kdev.devt = minor->device; - minor->kdev.type = &drm_sysfs_device_minor; if (minor->type == DRM_MINOR_CONTROL) minor_str = "controlD%d"; else if (minor->type == DRM_MINOR_RENDER) @@ -502,18 +515,34 @@ int drm_sysfs_device_add(struct drm_minor *minor) else minor_str = "card%d"; - dev_set_name(&minor->kdev, minor_str, minor->index); - - err = device_register(&minor->kdev); - if (err) { - DRM_ERROR("device add failed: %d\n", err); - goto err_out; + minor->kdev = kzalloc(sizeof(*minor->kdev), GFP_KERNEL); + if (!minor->kdev) { + r = -ENOMEM; + goto error; } + device_initialize(minor->kdev); + minor->kdev->devt = MKDEV(DRM_MAJOR, minor->index); + minor->kdev->class = drm_class; + minor->kdev->type = &drm_sysfs_device_minor; + minor->kdev->parent = minor->dev->dev; + minor->kdev->release = drm_sysfs_release; + dev_set_drvdata(minor->kdev, minor); + + r = dev_set_name(minor->kdev, minor_str, minor->index); + if (r < 0) + goto error; + + r = device_add(minor->kdev); + if (r < 0) + goto error; + return 0; -err_out: - return err; +error: + DRM_ERROR("device create failed %d\n", r); + put_device(minor->kdev); + return r; } /** @@ -525,7 +554,9 @@ err_out: */ void drm_sysfs_device_remove(struct drm_minor *minor) { - device_unregister(&minor->kdev); + if (minor->kdev) + device_unregister(minor->kdev); + minor->kdev = NULL; } @@ -541,6 +572,9 @@ void drm_sysfs_device_remove(struct drm_minor *minor) int drm_class_device_register(struct device *dev) { + if (!drm_class || IS_ERR(drm_class)) + return -ENOENT; + dev->class = drm_class; return device_register(dev); } |
