From 10937cf20b6814e4cf68114fab4619fad94eafcb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jan 2008 16:12:24 +1100 Subject: drm: move drm_head to drm_minor and fix up users --- linux-core/drm_sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3aaac11b..1f2d763b 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -154,7 +154,7 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) { int err; int i, j; @@ -162,8 +162,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) dev->dev.parent = &dev->pdev->dev; dev->dev.class = drm_class; dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = head->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + dev->dev.devt = minor->device; + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor); err = device_register(&dev->dev); if (err) { -- cgit v1.2.3 From d3da253adbf471c9af9c68b2ff67cbf516856352 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jan 2008 17:49:40 +1100 Subject: drm: add initial support for a drm control device node --- linux-core/drm_sysfs.c | 53 +++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 1f2d763b..a56e9959 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,7 +19,7 @@ #include "drm_core.h" #include "drmP.h" -#define to_drm_device(d) container_of(d, struct drm_device, dev) +#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) /** * drm_sysfs_suspend - DRM class suspend hook @@ -31,7 +31,8 @@ */ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; printk(KERN_ERR "%s\n", __FUNCTION__); @@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) */ static int drm_sysfs_resume(struct device *dev) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; if (drm_dev->driver->resume) return drm_dev->driver->resume(drm_dev); @@ -122,10 +124,11 @@ void drm_sysfs_destroy(void) static ssize_t show_dri(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_device *dev = to_drm_device(device); - if (dev->driver->dri_library_name) - return dev->driver->dri_library_name(dev, buf); - return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); + struct drm_minor *drm_minor = to_drm_minor(device); + struct drm_device *drm_dev = drm_minor->dev; + if (drm_dev->driver->dri_library_name) + return drm_dev->driver->dri_library_name(drm_dev, buf); + return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } static struct device_attribute device_attrs[] = { @@ -154,25 +157,31 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) +int drm_sysfs_device_add(struct drm_minor *minor) { int err; int i, j; - - dev->dev.parent = &dev->pdev->dev; - dev->dev.class = drm_class; - dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = minor->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor); - - err = device_register(&dev->dev); + 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; + if (minor->type == DRM_MINOR_CONTROL) + minor_str = "controlD%d"; + else + minor_str = "card%d"; + + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor); + + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); goto err_out; } for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&dev->dev, &device_attrs[i]); + err = device_create_file(&minor->kdev, &device_attrs[i]); if (err) goto err_out_files; } @@ -182,8 +191,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); err_out: return err; @@ -196,11 +205,11 @@ err_out: * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct drm_device *dev) +void drm_sysfs_device_remove(struct drm_minor *minor) { int i; for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); } -- cgit v1.2.3 From 135f51306b08f9863d77ac85b69989288c62f147 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 16:21:56 +1100 Subject: drm: only call suspend/resume on control node --- linux-core/drm_sysfs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index a56e9959..114e355e 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -36,8 +36,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) printk(KERN_ERR "%s\n", __FUNCTION__); - if (drm_dev->driver->suspend) - return drm_dev->driver->suspend(drm_dev); + if (drm_minor->type == DRM_MINOR_CONTROL) + if (drm_dev->driver->suspend) + return drm_dev->driver->suspend(drm_dev); return 0; } @@ -54,8 +55,9 @@ 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; - if (drm_dev->driver->resume) - return drm_dev->driver->resume(drm_dev); + if (drm_minor->type == DRM_MINOR_CONTROL) + if (drm_dev->driver->resume) + return drm_dev->driver->resume(drm_dev); return 0; } @@ -168,7 +170,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.release = drm_sysfs_device_release; minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) - minor_str = "controlD%d"; + minor_str = "controlD%d"; else minor_str = "card%d"; -- cgit v1.2.3 From f276c845bde4c712aa383540a2dd2055ecc00031 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Feb 2008 12:12:52 +1000 Subject: drm: re-write minor number allocation to use an idr. Fixup the minor number allocation scheme to use an idr and move the control nodes up higher. --- linux-core/drm_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 114e355e..cd03da8a 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -170,11 +170,11 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.release = drm_sysfs_device_release; minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) - minor_str = "controlD%d"; + minor_str = "controlD%d"; else minor_str = "card%d"; - snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor); + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); err = device_register(&minor->kdev); if (err) { -- cgit v1.2.3 From 75b01cf996f2efdd72c5280238460443d5d1fbc7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Feb 2008 10:04:28 +1000 Subject: switch naming to new proposed scheme --- linux-core/drm_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index cd03da8a..f03e5d4e 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -171,6 +171,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) minor_str = "controlD%d"; + else if (minor->type == DRM_MINOR_RENDER) + minor_str = "renderD%d"; else minor_str = "card%d"; -- cgit v1.2.3 From 5a3ce06f3a3dfa9412b9660c1e1f35d24c815dbb Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 8 Apr 2008 12:42:23 -0700 Subject: Improved DRM sysfs support This patch ties outputs, output properties and hotplug events into the DRM core. Each output has a corresponding directory under the primary DRM device (usually card0) containing dpms, edid, modes, and connection status files. New hotplug change events occur when outputs are added or hotplug events are detected. --- linux-core/drm_sysfs.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 188 insertions(+), 9 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3372a713..3e682c99 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -133,10 +133,6 @@ static ssize_t show_dri(struct device *device, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } -static struct device_attribute device_attrs[] = { - __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), -}; - /** * drm_sysfs_device_release - do nothing * @dev: Linux device @@ -150,6 +146,189 @@ static void drm_sysfs_device_release(struct device *dev) return; } +/* + * Output properties + */ +static ssize_t status_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + return snprintf(buf, PAGE_SIZE, "%s", + drm_get_output_status_name(output->funcs->detect(output))); +} + +static ssize_t dpms_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_device *dev = output->dev; + uint64_t dpms_status; + int ret; + + ret = drm_output_property_get_value(output, + dev->mode_config.dpms_property, + &dpms_status); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); +} + +static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *output_dev = container_of(kobj, struct device, kobj); + struct drm_output *output = container_of(output_dev, struct drm_output, + kdev); + unsigned char *edid; + size_t size; + + if (!output->edid_blob_ptr) + return 0; + + edid = output->edid_blob_ptr->data; + size = output->edid_blob_ptr->length; + if (!edid) + return 0; + + if (off >= size) + return 0; + + if (off + count > size) + count = size - off; + memcpy(buf, edid + off, count); + + return count; +} + +static ssize_t modes_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_display_mode *mode; + int written = 0; + + list_for_each_entry(mode, &output->modes, head) { + written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", + mode->name); + } + + return written; +} + +static struct device_attribute output_attrs[] = { + __ATTR_RO(status), + __ATTR_RO(dpms), + __ATTR_RO(modes), +}; + +static struct bin_attribute edid_attr = { + .attr.name = "edid", + .size = 128, + .read = edid_show, +}; + +/** + * drm_sysfs_output_add - add an output to sysfs + * @output: output to add + * + * Create an output device in sysfs, along with its associated output + * properties (so far, connection status, dpms, mode list & edid) and + * generate a hotplug event so userspace knows there's a new output + * available. + */ +int drm_sysfs_output_add(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + int ret = 0, i, j; + + if (device_is_registered(&output->kdev)) + return 0; + + output->kdev.parent = &dev->primary->kdev; + output->kdev.class = drm_class; + output->kdev.release = drm_sysfs_device_release; + + DRM_DEBUG("adding \"%s\" to sysfs", drm_get_output_name(output)); + + snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", + dev->primary->index, drm_get_output_name(output)); + ret = device_register(&output->kdev); + + if (ret) { + DRM_ERROR("failed to register output device: %d\n", ret); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(output_attrs); i++) { + ret = device_create_file(&output->kdev, &output_attrs[i]); + if (ret) + goto err_out_files; + } + + ret = sysfs_create_bin_file(&output->kdev.kobj, &edid_attr); + if (ret) + goto err_out_files; + + /* Let userspace know we have a new output */ + drm_sysfs_hotplug_event(dev); + + return 0; + +err_out_files: + if (i > 0) + for (j = 0; j < i; j++) + device_remove_file(&output->kdev, &output_attrs[i]); + device_unregister(&output->kdev); + +out: + return ret; +} + +/** + * drm_sysfs_output_remove - remove an output device from sysfs + * @output: output to remove + * + * Remove @output and its associated attributes from sysfs. Note that + * the device model core will take care of sending the "remove" uevent + * at this time, so we don't need to do it. + */ +void drm_sysfs_output_remove(struct drm_output *output) +{ + int i; + + DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); + for (i = 0; i < i; i++) + device_remove_file(&output->kdev, &output_attrs[i]); + sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); + device_unregister(&output->kdev); +} + +/** + * drm_sysfs_hotplug_event - generate a DRM uevent + * @dev: DRM device + * + * Send a uevent for the DRM device specified by @dev. Currently we only + * set HOTPLUG=1 in the uevent environment, but this could be expanded to + * deal with other types of events. + */ +void drm_sysfs_hotplug_event(struct drm_device *dev) +{ + char *event_string = "HOTPLUG=1"; + char *envp[] = { event_string, NULL }; + + DRM_DEBUG("generating hotplug event\n"); + + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); +} + +static struct device_attribute dri_attrs[] = { + __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), +}; + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver * @dev: DRM device to be added @@ -184,8 +363,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) goto err_out; } - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&minor->kdev, &device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) { + err = device_create_file(&minor->kdev, &dri_attrs[i]); if (err) goto err_out_files; } @@ -195,7 +374,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&minor->kdev, &device_attrs[i]); + device_remove_file(&minor->kdev, &dri_attrs[i]); device_unregister(&minor->kdev); err_out: @@ -213,7 +392,7 @@ void drm_sysfs_device_remove(struct drm_minor *minor) { int i; - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&minor->kdev, &device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) + device_remove_file(&minor->kdev, &dri_attrs[i]); device_unregister(&minor->kdev); } -- cgit v1.2.3 From fa116081a919e716eb95fcfa421d93f10f6f0a4f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 11:30:15 -0700 Subject: Fixup sysfs output registration Put off registering new outputs with sysfs until they're properly configured, or we may get duplicates if the type hasn't been set yet (as is the case with SDVO initialization). This also means moving de-registration into the cleanup function instead of output destroy, since the latter occurs during the normal course of setup when an output isn't found (and therefore not registered with sysfs yet. --- linux-core/drm_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3e682c99..427a2e54 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -287,6 +287,7 @@ err_out_files: out: return ret; } +EXPORT_SYMBOL(drm_sysfs_output_add); /** * drm_sysfs_output_remove - remove an output device from sysfs @@ -306,6 +307,7 @@ void drm_sysfs_output_remove(struct drm_output *output) sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); device_unregister(&output->kdev); } +EXPORT_SYMBOL(drm_sysfs_output_remove); /** * drm_sysfs_hotplug_event - generate a DRM uevent -- cgit v1.2.3 From 256a96135e6b48f5d3545896f7226edea8c70a0c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 14:06:36 -0700 Subject: Add newline to debug output for output add --- linux-core/drm_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 427a2e54..ef73cc83 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -252,7 +252,7 @@ int drm_sysfs_output_add(struct drm_output *output) output->kdev.class = drm_class; output->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs", drm_get_output_name(output)); + DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_output_name(output)); snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", dev->primary->index, drm_get_output_name(output)); -- cgit v1.2.3 From c250104c8f81026b4191ec8b2a709ff7ab5baedb Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 18 Apr 2008 16:26:41 +0800 Subject: fix removing output_attrs fix a typo in removing output sysfs. Signed-off-by: Hong Liu --- linux-core/drm_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index ef73cc83..8691d156 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -302,7 +302,7 @@ void drm_sysfs_output_remove(struct drm_output *output) int i; DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); - for (i = 0; i < i; i++) + for (i = 0; i < ARRAY_SIZE(output_attrs); i++) device_remove_file(&output->kdev, &output_attrs[i]); sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); device_unregister(&output->kdev); -- cgit v1.2.3 From 9d38448ed33aaff324cc4bbe1e0878593e97d07d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:03:12 +1000 Subject: modesetting: the great renaming. Okay we have crtc, encoder and connectors. No more outputs exposed beyond driver internals I've broken intel tv connector stuff. Really for TV we should have one TV connector, with a sub property for the type of signal been driven over it --- linux-core/drm_sysfs.c | 92 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 8691d156..01a3c047 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -147,27 +147,27 @@ static void drm_sysfs_device_release(struct device *dev) } /* - * Output properties + * Connector properties */ static ssize_t status_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); return snprintf(buf, PAGE_SIZE, "%s", - drm_get_output_status_name(output->funcs->detect(output))); + drm_get_connector_status_name(connector->funcs->detect(connector))); } static ssize_t dpms_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); - struct drm_device *dev = output->dev; + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; uint64_t dpms_status; int ret; - ret = drm_output_property_get_value(output, + ret = drm_connector_property_get_value(connector, dev->mode_config.dpms_property, &dpms_status); if (ret) @@ -179,17 +179,17 @@ static ssize_t dpms_show(struct device *device, static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *output_dev = container_of(kobj, struct device, kobj); - struct drm_output *output = container_of(output_dev, struct drm_output, + struct device *connector_dev = container_of(kobj, struct device, kobj); + struct drm_connector *connector = container_of(connector_dev, struct drm_connector, kdev); unsigned char *edid; size_t size; - if (!output->edid_blob_ptr) + if (!connector->edid_blob_ptr) return 0; - edid = output->edid_blob_ptr->data; - size = output->edid_blob_ptr->length; + edid = connector->edid_blob_ptr->data; + size = connector->edid_blob_ptr->length; if (!edid) return 0; @@ -207,11 +207,11 @@ static ssize_t modes_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); struct drm_display_mode *mode; int written = 0; - list_for_each_entry(mode, &output->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", mode->name); } @@ -219,7 +219,7 @@ static ssize_t modes_show(struct device *device, return written; } -static struct device_attribute output_attrs[] = { +static struct device_attribute connector_attrs[] = { __ATTR_RO(status), __ATTR_RO(dpms), __ATTR_RO(modes), @@ -232,48 +232,48 @@ static struct bin_attribute edid_attr = { }; /** - * drm_sysfs_output_add - add an output to sysfs - * @output: output to add + * drm_sysfs_connector_add - add an connector to sysfs + * @connector: connector to add * - * Create an output device in sysfs, along with its associated output + * Create an 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 output + * generate a hotplug event so userspace knows there's a new connector * available. */ -int drm_sysfs_output_add(struct drm_output *output) +int drm_sysfs_connector_add(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; int ret = 0, i, j; - if (device_is_registered(&output->kdev)) + if (device_is_registered(&connector->kdev)) return 0; - output->kdev.parent = &dev->primary->kdev; - output->kdev.class = drm_class; - output->kdev.release = drm_sysfs_device_release; + connector->kdev.parent = &dev->primary->kdev; + connector->kdev.class = drm_class; + connector->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_output_name(output)); + DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_connector_name(connector)); - snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", - dev->primary->index, drm_get_output_name(output)); - ret = device_register(&output->kdev); + snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", + dev->primary->index, drm_get_connector_name(connector)); + ret = device_register(&connector->kdev); if (ret) { - DRM_ERROR("failed to register output device: %d\n", ret); + DRM_ERROR("failed to register connector device: %d\n", ret); goto out; } - for (i = 0; i < ARRAY_SIZE(output_attrs); i++) { - ret = device_create_file(&output->kdev, &output_attrs[i]); + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { + ret = device_create_file(&connector->kdev, &connector_attrs[i]); if (ret) goto err_out_files; } - ret = sysfs_create_bin_file(&output->kdev.kobj, &edid_attr); + ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); if (ret) goto err_out_files; - /* Let userspace know we have a new output */ + /* Let userspace know we have a new connector */ drm_sysfs_hotplug_event(dev); return 0; @@ -281,33 +281,33 @@ int drm_sysfs_output_add(struct drm_output *output) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&output->kdev, &output_attrs[i]); - device_unregister(&output->kdev); + device_remove_file(&connector->kdev, &connector_attrs[i]); + device_unregister(&connector->kdev); out: return ret; } -EXPORT_SYMBOL(drm_sysfs_output_add); +EXPORT_SYMBOL(drm_sysfs_connector_add); /** - * drm_sysfs_output_remove - remove an output device from sysfs - * @output: output to remove + * drm_sysfs_connector_remove - remove an connector device from sysfs + * @connector: connector to remove * - * Remove @output and its associated attributes from sysfs. Note that + * Remove @connector and its associated attributes from sysfs. Note that * the device model core will take care of sending the "remove" uevent * at this time, so we don't need to do it. */ -void drm_sysfs_output_remove(struct drm_output *output) +void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; - DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); - for (i = 0; i < ARRAY_SIZE(output_attrs); i++) - device_remove_file(&output->kdev, &output_attrs[i]); - sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); - device_unregister(&output->kdev); + DRM_DEBUG("removing \"%s\" from sysfs\n", 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); } -EXPORT_SYMBOL(drm_sysfs_output_remove); +EXPORT_SYMBOL(drm_sysfs_connector_remove); /** * drm_sysfs_hotplug_event - generate a DRM uevent -- cgit v1.2.3 From 9f31bd09c1e748f72a30f6a0861cd72d93258992 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:16:49 +1000 Subject: drm/sysfs: don't try an unregister if not registered --- linux-core/drm_sysfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 01a3c047..c148256a 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -301,6 +301,9 @@ void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; + if (!device_is_registered(&connector->kdev)) + return; + DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_connector_name(connector)); for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) device_remove_file(&connector->kdev, &connector_attrs[i]); -- cgit v1.2.3 From 03bf1fba67413f381d2a548fe08bd634a48fcc48 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 5 Jun 2008 15:58:43 -0700 Subject: sysfs registration/teardown fixups A check in drm_sysfs_connector_remove was supposed to allow it to be called even with unregistered objects, to make cleanup paths a little simpler. However, device_is_regsitered didn't always seem to return what we thought it would, so we'd sometimes end up leaving objects lying around rather than unregistering them. Fix this situation up by requiring devices to be registered before being removed. Any problems resulting from this change should be easier to track down than the alternative (which is leaving kobjects registered after unload). --- linux-core/drm_sysfs.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index c148256a..92371c22 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -239,20 +239,26 @@ static struct bin_attribute edid_attr = { * 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) { struct drm_device *dev = connector->dev; int ret = 0, i, j; - if (device_is_registered(&connector->kdev)) - return 0; + /* We shouldn't get called more than once for the same connector */ + BUG_ON(device_is_registered(&connector->kdev)); connector->kdev.parent = &dev->primary->kdev; connector->kdev.class = drm_class; connector->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_connector_name(connector)); + DRM_DEBUG("adding \"%s\" to sysfs\n", + drm_get_connector_name(connector)); snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", dev->primary->index, drm_get_connector_name(connector)); @@ -296,15 +302,19 @@ EXPORT_SYMBOL(drm_sysfs_connector_add); * Remove @connector and its associated attributes from sysfs. Note that * the device model core will take care of sending the "remove" uevent * at this time, so we don't need to do it. + * + * Note: + * This routine should only be called if the connector was previously + * successfully registered. If @connector hasn't been registered yet, + * you'll likely see a panic somewhere deep in sysfs code when called. */ void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; - if (!device_is_registered(&connector->kdev)) - return; + DRM_DEBUG("removing \"%s\" from sysfs\n", + drm_get_connector_name(connector)); - DRM_DEBUG("removing \"%s\" from sysfs\n", 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); @@ -342,6 +352,11 @@ static struct device_attribute dri_attrs[] = { * Add a DRM device to the DRM's device model class. We use @dev's PCI device * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). + * + * 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_device_add(struct drm_minor *minor) { @@ -362,6 +377,11 @@ int drm_sysfs_device_add(struct drm_minor *minor) snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); + /* Shouldn't register more than once */ + BUG_ON(device_is_registered(&minor->kdev)); + + DRM_DEBUG("registering DRM device \"%s\"\n", minor->kdev.bus_id); + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); -- cgit v1.2.3 From 02b30739f7676082af4ce92448d910085d1dfc65 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 01:05:07 +0200 Subject: [modeseting-101] add connected field to sysfs --- linux-core/drm_sysfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 92371c22..02b08534 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,6 +176,19 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } +static ssize_t connected_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + + if (connector->encoder) + return snprintf(buf, PAGE_SIZE, "connected"); + else + return snprintf(buf, PAGE_SIZE, "disconnected"); +} + static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { @@ -221,6 +234,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), + __ATTR_RO(connected), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From d5ca5c9cd379438ac303598677f3789adc3687b1 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 08:07:35 +0200 Subject: [drm-sysfs] connected is ambigious in the context of a connector, replace with enabled --- linux-core/drm_sysfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 02b08534..36b92224 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,17 +176,16 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } -static ssize_t connected_show(struct device *device, +static ssize_t enabled_show(struct device *device, struct device_attribute *attr, char *buf) { struct drm_connector *connector = container_of(device, struct drm_connector, kdev); - struct drm_device *dev = connector->dev; if (connector->encoder) - return snprintf(buf, PAGE_SIZE, "connected"); + return snprintf(buf, PAGE_SIZE, "enabled"); else - return snprintf(buf, PAGE_SIZE, "disconnected"); + return snprintf(buf, PAGE_SIZE, "disabled"); } static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, @@ -234,7 +233,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), - __ATTR_RO(connected), + __ATTR_RO(enabled), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From b29578103f57a8d684b4a3a79f220e6cc626605e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:17:11 +0200 Subject: [modesetting-101] Add subconnector and select_subconnector properties. - These facilitate DVI-I and tv-out that can drive multiple types of signals. --- linux-core/drm_sysfs.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 36b92224..5c384a60 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -231,6 +231,78 @@ static ssize_t modes_show(struct device *device, return written; } +static ssize_t subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + 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: + prop = dev->mode_config.tv_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_subconnector_name((int)subconnector)); +} + +static ssize_t select_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + 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: + prop = dev->mode_config.tv_select_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find select subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_select_subconnector_name((int)subconnector)); +} + static struct device_attribute connector_attrs[] = { __ATTR_RO(status), __ATTR_RO(enabled), @@ -238,6 +310,12 @@ static struct device_attribute connector_attrs[] = { __ATTR_RO(modes), }; +/* These attributes are for both DVI-I connectors and all types of tv-out. */ +static struct device_attribute connector_attrs_opt1[] = { + __ATTR_RO(subconnector), + __ATTR_RO(select_subconnector), +}; + static struct bin_attribute edid_attr = { .attr.name = "edid", .size = 128, @@ -282,12 +360,32 @@ int drm_sysfs_connector_add(struct drm_connector *connector) goto out; } + /* Standard attributes */ + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { ret = device_create_file(&connector->kdev, &connector_attrs[i]); if (ret) goto err_out_files; } + /* Optional attributes */ + /* On 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: + for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) { + ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]); + 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; -- cgit v1.2.3 From 2b7feebb8ad5f49391b4f6bd6fc548e4f93b94f3 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 9 Aug 2008 19:33:32 +0200 Subject: NV50: call drm_sysfs_hotplug_event when appropriate --- linux-core/drm_sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_sysfs.c') diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 5c384a60..3b217342 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -450,6 +450,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); } +EXPORT_SYMBOL(drm_sysfs_hotplug_event); static struct device_attribute dri_attrs[] = { __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), -- cgit v1.2.3