diff options
Diffstat (limited to 'kernel/drivers/gpu/drm/drm_sysfs.c')
-rw-r--r-- | kernel/drivers/gpu/drm/drm_sysfs.c | 221 |
1 files changed, 123 insertions, 98 deletions
diff --git a/kernel/drivers/gpu/drm/drm_sysfs.c b/kernel/drivers/gpu/drm/drm_sysfs.c index eb7e61078..615b7e667 100644 --- a/kernel/drivers/gpu/drm/drm_sysfs.c +++ b/kernel/drivers/gpu/drm/drm_sysfs.c @@ -30,6 +30,8 @@ static struct device_type drm_sysfs_device_minor = { .name = "drm_minor" }; +struct class *drm_class; + /** * __drm_class_suspend - internal DRM class suspend routine * @dev: Linux device to suspend @@ -112,41 +114,34 @@ static CLASS_ATTR_STRING(version, S_IRUGO, CORE_DATE); /** - * drm_sysfs_create - create a struct drm_sysfs_class structure - * @owner: pointer to the module that is to "own" this struct drm_sysfs_class - * @name: pointer to a string for the name of this class. + * drm_sysfs_init - initialize sysfs helpers + * + * This is used to create the DRM class, which is the implicit parent of any + * other top-level DRM sysfs objects. * - * This is used to create DRM class pointer that can then be used - * in calls to drm_sysfs_device_add(). + * You must call drm_sysfs_destroy() to release the allocated resources. * - * Note, the pointer created here is to be destroyed when finished by making a - * call to drm_sysfs_destroy(). + * Return: 0 on success, negative error code on failure. */ -struct class *drm_sysfs_create(struct module *owner, char *name) +int drm_sysfs_init(void) { - struct class *class; int err; - class = class_create(owner, name); - if (IS_ERR(class)) { - err = PTR_ERR(class); - goto err_out; - } - - class->pm = &drm_class_dev_pm_ops; + drm_class = class_create(THIS_MODULE, "drm"); + if (IS_ERR(drm_class)) + return PTR_ERR(drm_class); - err = class_create_file(class, &class_attr_version.attr); - if (err) - goto err_out_class; + drm_class->pm = &drm_class_dev_pm_ops; - class->devnode = drm_devnode; - - return class; + err = class_create_file(drm_class, &class_attr_version.attr); + if (err) { + class_destroy(drm_class); + drm_class = NULL; + return err; + } -err_out_class: - class_destroy(class); -err_out: - return ERR_PTR(err); + drm_class->devnode = drm_devnode; + return 0; } /** @@ -156,7 +151,7 @@ err_out: */ void drm_sysfs_destroy(void) { - if ((drm_class == NULL) || (IS_ERR(drm_class))) + if (IS_ERR_OR_NULL(drm_class)) return; class_remove_file(drm_class, &class_attr_version.attr); class_destroy(drm_class); @@ -235,18 +230,12 @@ static ssize_t dpms_show(struct device *device, char *buf) { struct drm_connector *connector = to_drm_connector(device); - struct drm_device *dev = connector->dev; - uint64_t dpms_status; - int ret; + int dpms; - ret = drm_object_property_get_value(&connector->base, - dev->mode_config.dpms_property, - &dpms_status); - if (ret) - return 0; + dpms = READ_ONCE(connector->dpms); return snprintf(buf, PAGE_SIZE, "%s\n", - drm_get_dpms_name((int)dpms_status)); + drm_get_dpms_name(dpms)); } static ssize_t enabled_show(struct device *device, @@ -302,35 +291,43 @@ static ssize_t modes_show(struct device *device, return written; } -static ssize_t subconnector_show(struct device *device, - struct device_attribute *attr, - char *buf) +static ssize_t tv_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) { struct drm_connector *connector = to_drm_connector(device); struct drm_device *dev = connector->dev; - struct drm_property *prop = NULL; + struct drm_property *prop; uint64_t subconnector; - int is_tv = 0; int ret; - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - prop = dev->mode_config.dvi_i_subconnector_property; - break; - case DRM_MODE_CONNECTOR_Composite: - case DRM_MODE_CONNECTOR_SVIDEO: - case DRM_MODE_CONNECTOR_Component: - case DRM_MODE_CONNECTOR_TV: - prop = dev->mode_config.tv_subconnector_property; - is_tv = 1; - break; - default: - DRM_ERROR("Wrong connector type for this property\n"); - return 0; + prop = dev->mode_config.tv_subconnector_property; + if (!prop) { + DRM_ERROR("Unable to find subconnector property\n"); + return 0; } + ret = drm_object_property_get_value(&connector->base, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", + drm_get_tv_subconnector_name((int)subconnector)); +} + +static ssize_t tv_select_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = to_drm_connector(device); + struct drm_device *dev = connector->dev; + struct drm_property *prop; + uint64_t subconnector; + int ret; + + prop = dev->mode_config.tv_select_subconnector_property; if (!prop) { - DRM_ERROR("Unable to find subconnector property\n"); + DRM_ERROR("Unable to find select subconnector property\n"); return 0; } @@ -338,38 +335,45 @@ static ssize_t subconnector_show(struct device *device, if (ret) return 0; - return snprintf(buf, PAGE_SIZE, "%s", is_tv ? - drm_get_tv_subconnector_name((int)subconnector) : - drm_get_dvi_i_subconnector_name((int)subconnector)); + return snprintf(buf, PAGE_SIZE, "%s", + drm_get_tv_select_name((int)subconnector)); } -static ssize_t select_subconnector_show(struct device *device, - struct device_attribute *attr, - char *buf) +static ssize_t dvii_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) { struct drm_connector *connector = to_drm_connector(device); struct drm_device *dev = connector->dev; - struct drm_property *prop = NULL; + struct drm_property *prop; uint64_t subconnector; - int is_tv = 0; int ret; - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - prop = dev->mode_config.dvi_i_select_subconnector_property; - break; - case DRM_MODE_CONNECTOR_Composite: - case DRM_MODE_CONNECTOR_SVIDEO: - case DRM_MODE_CONNECTOR_Component: - case DRM_MODE_CONNECTOR_TV: - prop = dev->mode_config.tv_select_subconnector_property; - is_tv = 1; - break; - default: - DRM_ERROR("Wrong connector type for this property\n"); - return 0; + prop = dev->mode_config.dvi_i_subconnector_property; + if (!prop) { + DRM_ERROR("Unable to find subconnector property\n"); + return 0; } + ret = drm_object_property_get_value(&connector->base, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", + drm_get_dvi_i_subconnector_name((int)subconnector)); +} + +static ssize_t dvii_select_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = to_drm_connector(device); + struct drm_device *dev = connector->dev; + struct drm_property *prop; + uint64_t subconnector; + int ret; + + prop = dev->mode_config.dvi_i_select_subconnector_property; if (!prop) { DRM_ERROR("Unable to find select subconnector property\n"); return 0; @@ -379,8 +383,7 @@ static ssize_t select_subconnector_show(struct device *device, if (ret) return 0; - return snprintf(buf, PAGE_SIZE, "%s", is_tv ? - drm_get_tv_select_name((int)subconnector) : + return snprintf(buf, PAGE_SIZE, "%s", drm_get_dvi_i_select_name((int)subconnector)); } @@ -397,28 +400,44 @@ static struct attribute *connector_dev_attrs[] = { NULL }; -/* These attributes are for both DVI-I connectors and all types of tv-out. */ -static DEVICE_ATTR_RO(subconnector); -static DEVICE_ATTR_RO(select_subconnector); +static DEVICE_ATTR_RO(tv_subconnector); +static DEVICE_ATTR_RO(tv_select_subconnector); + +static struct attribute *connector_tv_dev_attrs[] = { + &dev_attr_tv_subconnector.attr, + &dev_attr_tv_select_subconnector.attr, + NULL +}; + +static DEVICE_ATTR_RO(dvii_subconnector); +static DEVICE_ATTR_RO(dvii_select_subconnector); -static struct attribute *connector_opt_dev_attrs[] = { - &dev_attr_subconnector.attr, - &dev_attr_select_subconnector.attr, +static struct attribute *connector_dvii_dev_attrs[] = { + &dev_attr_dvii_subconnector.attr, + &dev_attr_dvii_select_subconnector.attr, NULL }; -static umode_t connector_opt_dev_is_visible(struct kobject *kobj, - struct attribute *attr, int idx) +/* Connector type related helpers */ +static int kobj_connector_type(struct kobject *kobj) { struct device *dev = kobj_to_dev(kobj); struct drm_connector *connector = to_drm_connector(dev); - /* - * In the long run it maybe a good idea to make one set of - * optionals per connector type. - */ - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DVII: + return connector->connector_type; +} + +static umode_t connector_is_dvii(struct kobject *kobj, + struct attribute *attr, int idx) +{ + return kobj_connector_type(kobj) == DRM_MODE_CONNECTOR_DVII ? + attr->mode : 0; +} + +static umode_t connector_is_tv(struct kobject *kobj, + struct attribute *attr, int idx) +{ + switch (kobj_connector_type(kobj)) { case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Component: @@ -446,14 +465,20 @@ static const struct attribute_group connector_dev_group = { .bin_attrs = connector_bin_attrs, }; -static const struct attribute_group connector_opt_dev_group = { - .attrs = connector_opt_dev_attrs, - .is_visible = connector_opt_dev_is_visible, +static const struct attribute_group connector_tv_dev_group = { + .attrs = connector_tv_dev_attrs, + .is_visible = connector_is_tv, +}; + +static const struct attribute_group connector_dvii_dev_group = { + .attrs = connector_dvii_dev_attrs, + .is_visible = connector_is_dvii, }; static const struct attribute_group *connector_dev_groups[] = { &connector_dev_group, - &connector_opt_dev_group, + &connector_tv_dev_group, + &connector_dvii_dev_group, NULL }; |