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);  }  | 
