summaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-05-08 14:26:47 +0100
committerDave Airlie <airlied@redhat.com>2012-07-06 10:20:19 +0100
commitcf66471353ac5899383b573a3cfca407e90d501e (patch)
tree1bb65b5d4bb7451a1431ac73ec8935e4f668ca44 /config
parent2c52d776a42a28bb3e1463edf0cfe0672d0c08a9 (diff)
xfree86: use udev to provide device enumeration for kms devices (v10)
On Linux in order for future hotplug work, we are required to interface to udev to detect device creation/removal. In order to try and get some earlier testing on this, this patch adds the ability to use udev for device enumeration on Linux. At startup the list of drm/kms devices is probed and this info is used to load drivers. A new driver probing method is introduced that passes the udev device info to the driver for probing. The probing integrates with the pci probing code and will fallback to the pci probe and old school probe functions in turn. The flags parameter to the probe function will be used later to provide hotplug and gpu screen flags for the driver to behave in a different way. This patch changes the driver ABI, all drivers should at least be set with a NULL udev probe function after this commit. v2: rename to platform bus, now with 100% less udev specific, this version passes config_odev_attribs around which are an array of id/string pairs, then the udev code can attach the set of attribs it understands, the OS specific code can attach its attrib, and then the core/drivers can lookup the required attribs. also add MATCH_PCI_DEVICES macro. This version is mainly to address concerns raised by ajax. v3: Address comments from Peter. fix whitespace that snuck in. rework to use a linked list with some core functions that xf86 wraps. v4: add free list, fix struct whitespace. ajax this address most of your issues? v5: drop probe ifdef, fix logic issue v6: some overhaul after more testing. Implement primaryBus for platform devices. document hotplug.h dev attribs - drop sysname attrib fix build with udev kms disabled make probing work like the PCI probe code, match against bus id if one exists, or primary device. RFC: add new bus id support "PLAT:syspath". we probably want to match on this a bit different, or use a different property maybe. I was mainly wanting this for use with specifying usb devices in xorg.conf directly, but PLAT:path could also work I suppose. v6.1: add missing noop platform function v7: fix two interactions with pci probing and slot claiming, prevents pci and platform trying to load two drivers for same slot. v8: test with zaphod mode on -ati driver, fixup resulting issue clean up common probe code into another function, change busid matching to allow dropping end of strings. v9: fix platform probing logic so it actually works. v9.1: fix pdev init to NULL properly. v10: address most of Keith's concerns. v4 was thanks to Reviewed-by: Adam Jackson <ajax@redhat.com> v5 was Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'config')
-rw-r--r--config/config-backends.h1
-rw-r--r--config/config.c56
-rw-r--r--config/udev.c69
3 files changed, 126 insertions, 0 deletions
diff --git a/config/config-backends.h b/config/config-backends.h
index 62abc0a5f..6423701fc 100644
--- a/config/config-backends.h
+++ b/config/config-backends.h
@@ -36,6 +36,7 @@ BOOL device_is_duplicate(const char *config_info);
int config_udev_pre_init(void);
int config_udev_init(void);
void config_udev_fini(void);
+void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
#else
#ifdef CONFIG_NEED_DBUS
diff --git a/config/config.c b/config/config.c
index 24e7ba7a0..d0889a394 100644
--- a/config/config.c
+++ b/config/config.c
@@ -85,6 +85,14 @@ config_fini(void)
#endif
}
+void
+config_odev_probe(config_odev_probe_proc_ptr probe_callback)
+{
+#if defined(CONFIG_UDEV_KMS)
+ config_udev_odev_probe(probe_callback);
+#endif
+}
+
static void
remove_device(const char *backend, DeviceIntPtr dev)
{
@@ -133,3 +141,51 @@ device_is_duplicate(const char *config_info)
return FALSE;
}
+
+struct OdevAttributes *
+config_odev_allocate_attribute_list(void)
+{
+ struct OdevAttributes *attriblist;
+
+ attriblist = malloc(sizeof(struct OdevAttributes));
+ if (!attriblist)
+ return NULL;
+
+ xorg_list_init(&attriblist->list);
+ return attriblist;
+}
+
+void
+config_odev_free_attribute_list(struct OdevAttributes *attribs)
+{
+ config_odev_free_attributes(attribs);
+ free(attribs);
+}
+
+Bool
+config_odev_add_attribute(struct OdevAttributes *attribs, int attrib,
+ const char *attrib_name)
+{
+ struct OdevAttribute *oa;
+
+ oa = malloc(sizeof(struct OdevAttribute));
+ if (!oa)
+ return FALSE;
+
+ oa->attrib_id = attrib;
+ oa->attrib_name = strdup(attrib_name);
+ xorg_list_append(&oa->member, &attribs->list);
+ return TRUE;
+}
+
+void
+config_odev_free_attributes(struct OdevAttributes *attribs)
+{
+ struct OdevAttribute *iter, *safe;
+
+ xorg_list_for_each_entry_safe(iter, safe, &attribs->list, member) {
+ xorg_list_del(&iter->member);
+ free(iter->attrib_name);
+ free(iter);
+ }
+}
diff --git a/config/udev.c b/config/udev.c
index 1995184f3..efa8d3257 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -366,3 +366,72 @@ config_udev_fini(void)
udev_monitor = NULL;
udev_unref(udev);
}
+
+#ifdef CONFIG_UDEV_KMS
+
+static Bool
+config_udev_odev_setup_attribs(const char *path, const char *syspath,
+ config_odev_probe_proc_ptr probe_callback)
+{
+ struct OdevAttributes *attribs = config_odev_allocate_attribute_list();
+ int ret;
+
+ if (!attribs)
+ return FALSE;
+
+ ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_PATH, path);
+ if (ret == FALSE)
+ goto fail;
+
+ ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_SYSPATH, syspath);
+ if (ret == FALSE)
+ goto fail;
+
+ /* ownership of attribs is passed to probe layer */
+ probe_callback(attribs);
+ return TRUE;
+fail:
+ config_odev_free_attributes(attribs);
+ free(attribs);
+ return FALSE;
+}
+
+void
+config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *device;
+
+ udev = udev_monitor_get_udev(udev_monitor);
+ enumerate = udev_enumerate_new(udev);
+ if (!enumerate)
+ return;
+
+ udev_enumerate_add_match_subsystem(enumerate, "drm");
+ udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(device, devices) {
+ const char *syspath = udev_list_entry_get_name(device);
+ struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
+ const char *path = udev_device_get_devnode(udev_device);
+ const char *sysname = udev_device_get_sysname(udev_device);
+
+ if (!path || !syspath)
+ goto no_probe;
+ else if (strcmp(udev_device_get_subsystem(udev_device), "drm") != 0)
+ goto no_probe;
+ else if (strncmp(sysname, "card", 4) != 0)
+ goto no_probe;
+
+ config_udev_odev_setup_attribs(path, syspath, probe_callback);
+
+ no_probe:
+ udev_device_unref(udev_device);
+ }
+ udev_enumerate_unref(enumerate);
+ return;
+}
+#endif
+