compositor-fbdev: detect the first fb device in the seat
authornerdopolis <bluescreen_avenger@verizon.net>
Fri, 29 Jun 2018 12:17:50 +0000 (08:17 -0400)
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>
Mon, 2 Jul 2018 12:29:38 +0000 (15:29 +0300)
This adds a function to detect the first framebuffer device in the
current seat. Instead of hardcoding /dev/fb0, detect the device
with udev, favoring the boot_vga device, and falling back to the
first framebuffer device in the seat if there is none. This is very
similar to what compositor-drm does to find display devices

Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
libweston/compositor-fbdev.c

index 74971c3..a71b7bd 100644 (file)
@@ -778,6 +778,77 @@ session_notify(struct wl_listener *listener, void *data)
        }
 }
 
+static char *
+find_framebuffer_device(struct fbdev_backend *b, const char *seat)
+{
+       struct udev_enumerate *e;
+       struct udev_list_entry *entry;
+       const char *path, *device_seat, *id;
+       char *fb_device_path = NULL;
+       struct udev_device *device, *fb_device, *pci;
+
+       e = udev_enumerate_new(b->udev);
+       udev_enumerate_add_match_subsystem(e, "graphics");
+       udev_enumerate_add_match_sysname(e, "fb[0-9]*");
+
+       udev_enumerate_scan_devices(e);
+       fb_device = NULL;
+       udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+               bool is_boot_vga = false;
+
+               path = udev_list_entry_get_name(entry);
+               device = udev_device_new_from_syspath(b->udev, path);
+               if (!device)
+                       continue;
+               device_seat = udev_device_get_property_value(device, "ID_SEAT");
+               if (!device_seat)
+                       device_seat = default_seat;
+               if (strcmp(device_seat, seat)) {
+                       udev_device_unref(device);
+                       continue;
+               }
+
+               pci = udev_device_get_parent_with_subsystem_devtype(device,
+                                                               "pci", NULL);
+               if (pci) {
+                       id = udev_device_get_sysattr_value(pci, "boot_vga");
+                       if (id && !strcmp(id, "1"))
+                               is_boot_vga = true;
+               }
+
+               /* If a framebuffer device was found, and this device isn't
+                * the boot-VGA device, don't use it. */
+               if (!is_boot_vga && fb_device) {
+                       udev_device_unref(device);
+                       continue;
+               }
+
+               /* There can only be one boot_vga device. Try to use it
+                * at all costs. */
+               if (is_boot_vga) {
+                       if (fb_device)
+                               udev_device_unref(fb_device);
+                       fb_device = device;
+                       break;
+               }
+
+               /* Per the (!is_boot_vga && fb_device) test above, only
+                * trump existing saved devices with boot-VGA devices, so if
+                * the test ends up here, this must be the first device seen. */
+               assert(!fb_device);
+               fb_device = device;
+       }
+
+       udev_enumerate_unref(e);
+
+       if (fb_device) {
+               fb_device_path = strdup(udev_device_get_devnode(fb_device));
+               udev_device_unref(fb_device);
+       }
+
+       return fb_device_path;
+}
+
 static struct fbdev_backend *
 fbdev_backend_create(struct weston_compositor *compositor,
                      struct weston_fbdev_backend_config *param)
@@ -810,6 +881,13 @@ fbdev_backend_create(struct weston_compositor *compositor,
                goto out_compositor;
        }
 
+       if (!param->device)
+               param->device = find_framebuffer_device(backend, seat_id);
+       if (!param->device) {
+               weston_log("fatal: no framebuffer devices detected.\n");
+               goto out_udev;
+       }
+
        /* Set up the TTY. */
        backend->session_listener.notify = session_notify;
        wl_signal_add(&compositor->session_signal,
@@ -836,12 +914,15 @@ fbdev_backend_create(struct weston_compositor *compositor,
        if (!fbdev_head_create(backend, param->device))
                goto out_launcher;
 
+       free(param->device);
+
        udev_input_init(&backend->input, compositor, backend->udev,
                        seat_id, param->configure_device);
 
        return backend;
 
 out_launcher:
+       free(param->device);
        weston_launcher_destroy(compositor->launcher);
 
 out_udev:
@@ -857,10 +938,8 @@ out_compositor:
 static void
 config_init_to_defaults(struct weston_fbdev_backend_config *config)
 {
-       /* TODO: Ideally, available frame buffers should be enumerated using
-        * udev, rather than passing a device node in as a parameter. */
        config->tty = 0; /* default to current tty */
-       config->device = "/dev/fb0"; /* default frame buffer */
+       config->device = NULL;
        config->seat_id = NULL;
 }