From dbd5fa7e74dad4cfdea32d4d6188997f63cbd0b2 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 27 Oct 2012 17:46:48 +0200 Subject: [PATCH] uterm: monitor: mark auxiliary devices We now mark auxiliary displays specially so applications know which devices can be used independently. We currently only mark USB devices as such but this can be extended in the future for more devices. Signed-off-by: David Herrmann --- src/uterm.h | 1 + src/uterm_monitor.c | 106 ++++++++++++++++++++++++++++++------------ src/uterm_video.h | 11 +++++ src/uterm_video_drm.c | 30 ++++++++++++ 4 files changed, 117 insertions(+), 31 deletions(-) diff --git a/src/uterm.h b/src/uterm.h index 17ffd0f..5d11cd3 100644 --- a/src/uterm.h +++ b/src/uterm.h @@ -403,6 +403,7 @@ enum uterm_monitor_dev_type { enum uterm_monitor_dev_flag { UTERM_MONITOR_DRM_BACKED = 0x01, UTERM_MONITOR_PRIMARY = 0x02, + UTERM_MONITOR_AUX = 0x04, }; struct uterm_monitor_event { diff --git a/src/uterm_monitor.c b/src/uterm_monitor.c index 8480a9f..29b63fe 100644 --- a/src/uterm_monitor.c +++ b/src/uterm_monitor.c @@ -402,32 +402,48 @@ static int get_fb_id(struct udev_device *dev) } /* + * UTERM_MONITOR_DRM_BACKED: * Nearly all DRM drivers do also create fbdev nodes which refer to the same * hardware as the DRM devices. So we shouldn't advertise these fbdev nodes as * real devices. Otherwise, the user might use these and the DRM devices * simultaneously, thinking that they deal with two different hardware devices. - * * We also report that it is a drm-device if we actually cannot verify that it * is not some DRM device. + * + * UTERM_MONITOR_AUX: + * Auxiliary devices are devices that are not the main GPU but rather some kind + * of hotpluggable helpers that provide additional display controllers. This is + * some kind of whitelist that tells the application that this GPU can safely be + * used as additional GPU together with but also independent of the primary GPU. + * + * UTERM_MONITOR_PRIMARY: + * The primary GPU is the GPU that was used to boot the system. An application + * can always use this CPU without getting into troubles. For instance, under + * dual-GPU systems, there is often only one display controller but both DRM + * devices advertice modesetting capability. The application can now rely on + * this flag to mark the GPU that actually should be used for modesetting. The + * other GPU is neither PRIMARY nor AUX and shouldn't be used by the application + * except for offloading rendering-work or similar. */ -static bool is_drm_fbdev(const char *node) + +static unsigned int get_fbdev_flags(struct uterm_monitor *mon, const char *node) { int fd, ret, len; struct fb_fix_screeninfo finfo; - bool res = true; + unsigned int flags = UTERM_MONITOR_DRM_BACKED; fd = open(node, O_RDWR | O_CLOEXEC); if (fd < 0) { log_warning("cannot open fbdev node %s for drm-device verification (%d): %m", node, errno); - return true; + return flags; } ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo); if (ret) { log_warning("cannot retrieve finfo from fbdev node %s for drm-device verification (%d): %m", node, errno); - goto err_close; + goto out_close; } /* TODO: we really need some reliable flag here that tells us that we @@ -437,45 +453,34 @@ static bool is_drm_fbdev(const char *node) * checking whether the parent udev device node does also provide a DRM * device. */ len = strlen(finfo.id); - if (len > 5 && !strcmp(&finfo.id[len - 5], "drmfb")) - goto err_close; - if (!strcmp(finfo.id, "nouveaufb")) - goto err_close; - if (!strcmp(finfo.id, "psbfb")) - goto err_close; + if ((len < 5 || strcmp(&finfo.id[len - 5], "drmfb")) && + strcmp(finfo.id, "nouveaufb") && + strcmp(finfo.id, "psbfb")) + flags &= ~UTERM_MONITOR_DRM_BACKED; - res = false; + if (!strcmp(finfo.id, "udlfb")) + flags |= UTERM_MONITOR_AUX; -err_close: +out_close: close(fd); - return res; + return flags; } -static bool is_drm_primary(struct uterm_monitor *mon, const char *node) +static bool is_drm_primary(struct uterm_monitor *mon, const char *node, int fd) { - int fd; char *id; bool res; if (!mon->pci_primary_id) return false; - fd = open(node, O_RDWR | O_CLOEXEC); - if (fd < 0) { - log_warning("cannot open DRM device %s for primary-detection (%d): %m", - node, errno); - return false; - } - id = video_drm_get_id(fd); if (!id) { log_warning("cannot get bus-id for DRM device %s (%d): %m", node, errno); - close(fd); return false; } - close(fd); res = !strcmp(id, mon->pci_primary_id); video_drm_free_id(id); @@ -484,6 +489,49 @@ static bool is_drm_primary(struct uterm_monitor *mon, const char *node) return res; } +static bool is_drm_usb(struct uterm_monitor *mon, const char *node, int fd) +{ + char *name; + bool res; + + name = video_drm_get_name(fd); + if (!name) { + log_warning("cannot get driver name for DRM device %s (%d): %m", + node, errno); + return false; + } + + if (!strcmp(name, "udl")) + res = true; + else + res = false; + + log_debug("DRM device %s uses driver %s", node, name); + video_drm_free_name(name); + return res; +} + +static unsigned int get_drm_flags(struct uterm_monitor *mon, const char *node) +{ + int fd; + unsigned int flags = 0; + + fd = open(node, O_RDWR | O_CLOEXEC); + if (fd < 0) { + log_warning("cannot open DRM device %s for primary-detection (%d): %m", + node, errno); + return flags; + } + + if (is_drm_primary(mon, node, fd)) + flags |= UTERM_MONITOR_PRIMARY; + if (is_drm_usb(mon, node, fd)) + flags |= UTERM_MONITOR_AUX; + + close(fd); + return flags; +} + static void monitor_udev_add(struct uterm_monitor *mon, struct udev_device *dev) { @@ -529,9 +577,7 @@ static void monitor_udev_add(struct uterm_monitor *mon, } sname = udev_device_get_property_value(dev, "ID_SEAT"); type = UTERM_MONITOR_DRM; - flags = 0; - if (is_drm_primary(mon, node)) - flags |= UTERM_MONITOR_PRIMARY; + flags = get_drm_flags(mon, node); } else if (!strcmp(subs, "graphics")) { #ifdef BUILD_ENABLE_MULTI_SEAT if (udev_device_has_tag(dev, "seat") != 1) { @@ -546,9 +592,7 @@ static void monitor_udev_add(struct uterm_monitor *mon, } sname = udev_device_get_property_value(dev, "ID_SEAT"); type = UTERM_MONITOR_FBDEV; - flags = 0; - if (is_drm_fbdev(node)) - flags |= UTERM_MONITOR_DRM_BACKED; + flags = get_fbdev_flags(mon, node); } else if (!strcmp(subs, "input")) { sysname = udev_device_get_sysname(dev); if (!sysname || strncmp(sysname, "event", 5)) { diff --git a/src/uterm_video.h b/src/uterm_video.h index 9ef3e2c..9d66ef8 100644 --- a/src/uterm_video.h +++ b/src/uterm_video.h @@ -422,6 +422,8 @@ static inline int video_do_use(struct uterm_video *video) char *video_drm_get_id(int fd); void video_drm_free_id(char *id); +char *video_drm_get_name(int fd); +void video_drm_free_name(char *name); #else @@ -434,6 +436,15 @@ static inline void video_drm_free_id(char *id) { } +static inline char *video_drm_get_name(int fd) +{ + return NULL; +} + +static inline void video_drm_free_name(char *name) +{ +} + #endif #endif /* UTERM_VIDEO_H */ diff --git a/src/uterm_video_drm.c b/src/uterm_video_drm.c index 6a17cdd..e0c3bc8 100644 --- a/src/uterm_video_drm.c +++ b/src/uterm_video_drm.c @@ -1267,6 +1267,36 @@ void video_drm_free_id(char *id) drmFreeBusid(id); } +char *video_drm_get_name(int fd) +{ + drmVersionPtr v; + char *name; + + if (fd < 0) + return NULL; + + v = drmGetVersion(fd); + if (!v) + return NULL; + + name = malloc(v->name_len + 1); + if (name) { + memcpy(name, v->name, v->name_len); + name[v->name_len] = 0; + } + + drmFreeVersion(v); + return name; +} + +void video_drm_free_name(char *name) +{ + if (!name) + return; + + free(name); +} + const struct mode_ops drm_mode_ops = { .init = NULL, .destroy = NULL,