drm: Use static attribute groups for managing connector sysfs entries

Instead of manual calls of device_create_file() and
device_remove_file(), assign the static attribute groups to the device
with device_create_with_groups().  The conditionally built sysfs
entries are handled via is_visible callback.

This simplifies the code and also avoids the possible races.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Takashi Iwai 2015-02-04 11:58:53 +01:00 committed by Daniel Vetter
parent 083500baef
commit 335f1a62c5
1 changed files with 67 additions and 65 deletions

View File

@ -339,19 +339,51 @@ static ssize_t select_subconnector_show(struct device *device,
drm_get_dvi_i_select_name((int)subconnector)); drm_get_dvi_i_select_name((int)subconnector));
} }
static struct device_attribute connector_attrs[] = { static DEVICE_ATTR_RO(status);
__ATTR_RO(status), static DEVICE_ATTR_RO(enabled);
__ATTR_RO(enabled), static DEVICE_ATTR_RO(dpms);
__ATTR_RO(dpms), static DEVICE_ATTR_RO(modes);
__ATTR_RO(modes),
static struct attribute *connector_dev_attrs[] = {
&dev_attr_status.attr,
&dev_attr_enabled.attr,
&dev_attr_dpms.attr,
&dev_attr_modes.attr,
NULL
}; };
/* These attributes are for both DVI-I connectors and all types of tv-out. */ /* These attributes are for both DVI-I connectors and all types of tv-out. */
static struct device_attribute connector_attrs_opt1[] = { static DEVICE_ATTR_RO(subconnector);
__ATTR_RO(subconnector), static DEVICE_ATTR_RO(select_subconnector);
__ATTR_RO(select_subconnector),
static struct attribute *connector_opt_dev_attrs[] = {
&dev_attr_subconnector.attr,
&dev_attr_select_subconnector.attr,
NULL
}; };
static umode_t connector_opt_dev_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
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:
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Component:
case DRM_MODE_CONNECTOR_TV:
return attr->mode;
}
return 0;
}
static struct bin_attribute edid_attr = { static struct bin_attribute edid_attr = {
.attr.name = "edid", .attr.name = "edid",
.attr.mode = 0444, .attr.mode = 0444,
@ -359,6 +391,27 @@ static struct bin_attribute edid_attr = {
.read = edid_show, .read = edid_show,
}; };
static struct bin_attribute *connector_bin_attrs[] = {
&edid_attr,
NULL
};
static const struct attribute_group connector_dev_group = {
.attrs = connector_dev_attrs,
.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_dev_groups[] = {
&connector_dev_group,
&connector_opt_dev_group,
NULL
};
/** /**
* drm_sysfs_connector_add - add a connector to sysfs * drm_sysfs_connector_add - add a connector to sysfs
* @connector: connector to add * @connector: connector to add
@ -371,73 +424,27 @@ static struct bin_attribute edid_attr = {
int drm_sysfs_connector_add(struct drm_connector *connector) int drm_sysfs_connector_add(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
int attr_cnt = 0;
int opt_cnt = 0;
int i;
int ret;
if (connector->kdev) if (connector->kdev)
return 0; return 0;
connector->kdev = device_create(drm_class, dev->primary->kdev, connector->kdev =
0, connector, "card%d-%s", device_create_with_groups(drm_class, dev->primary->kdev, 0,
dev->primary->index, connector->name); connector, connector_dev_groups,
"card%d-%s", dev->primary->index,
connector->name);
DRM_DEBUG("adding \"%s\" to sysfs\n", DRM_DEBUG("adding \"%s\" to sysfs\n",
connector->name); connector->name);
if (IS_ERR(connector->kdev)) { if (IS_ERR(connector->kdev)) {
DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev)); DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
ret = PTR_ERR(connector->kdev); return 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]);
if (ret)
goto err_out_files;
}
/* Optional attributes */
/*
* 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:
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_SVIDEO:
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]);
if (ret)
goto err_out_files;
}
break;
default:
break;
}
ret = sysfs_create_bin_file(&connector->kdev->kobj, &edid_attr);
if (ret)
goto err_out_files;
/* Let userspace know we have a new connector */ /* Let userspace know we have a new connector */
drm_sysfs_hotplug_event(dev); drm_sysfs_hotplug_event(dev);
return 0; return 0;
err_out_files:
for (i = 0; i < opt_cnt; 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);
out:
return ret;
} }
/** /**
@ -455,16 +462,11 @@ out:
*/ */
void drm_sysfs_connector_remove(struct drm_connector *connector) void drm_sysfs_connector_remove(struct drm_connector *connector)
{ {
int i;
if (!connector->kdev) if (!connector->kdev)
return; return;
DRM_DEBUG("removing \"%s\" from sysfs\n", DRM_DEBUG("removing \"%s\" from sysfs\n",
connector->name); 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_unregister(connector->kdev);
connector->kdev = NULL; connector->kdev = NULL;
} }