All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: airlied@linux.ie, daniel@ffwll.ch, b.zolnierkie@samsung.com
Cc: linux-fbdev@vger.kernel.org,
	Thomas Zimmermann <tzimmermann@suse.de>,
	dri-devel@lists.freedesktop.org
Subject: [PATCH 02/11] drm/fbdevdrm: Add fbdevdrm device
Date: Tue, 26 Mar 2019 09:17:35 +0000	[thread overview]
Message-ID: <20190326091744.11542-3-tzimmermann@suse.de> (raw)
In-Reply-To: <20190326091744.11542-1-tzimmermann@suse.de>

There's an fbdevdrm device for each supported fbdev device. The fbdevdrm
driver listens for fb events, and creates and destroys fbdevdrm devices
accordingly.

Only hardware-specific fbdev drivers are supported. Generic drivers, such
as vga16fb or vesafb are not handled. DRM-based fbdev drivers are also not
supported. This prevents the situation where a DRM drivers enables
framebuffer emulation and fbdevdrm creates a second DRM device for the
same hardware.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/fbdevdrm/Makefile          |   3 +-
 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c |  79 ++++++++++
 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h |  44 ++++++
 drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c    | 173 ++++++++++++++++++++-
 4 files changed, 296 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h

diff --git a/drivers/gpu/drm/fbdevdrm/Makefile b/drivers/gpu/drm/fbdevdrm/Makefile
index 65e6b43cf682..750940d38509 100644
--- a/drivers/gpu/drm/fbdevdrm/Makefile
+++ b/drivers/gpu/drm/fbdevdrm/Makefile
@@ -1,4 +1,5 @@
 ccflags-y = -Iinclude/drm
-fbdevdrm-y := fbdevdrm_drv.o
+fbdevdrm-y := fbdevdrm_device.o \
+	      fbdevdrm_drv.o
 
 obj-$(CONFIG_DRM_FBDEVDRM) += fbdevdrm.o
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
new file mode 100644
index 000000000000..0abf41cf05bb
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#include "fbdevdrm_device.h"
+#include <drm/drm_drv.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_print.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+/*
+ * struct fbdrmdev_device
+ */
+
+int fbdevdrm_device_init(struct fbdevdrm_device *fdev, struct drm_driver *drv,
+			 struct fb_info *fb_info)
+{
+	int ret;
+
+	ret = drm_dev_init(&fdev->dev, drv, fb_info->device);
+	if (ret)
+		return ret;
+	fdev->dev.dev_private = fdev;
+	fdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+	fdev->fb_info = fb_info;
+
+	INIT_LIST_HEAD(&fdev->device_list);
+
+	return 0;
+}
+
+void fbdevdrm_device_cleanup(struct fbdevdrm_device *fdev)
+{
+	struct drm_device *dev = &fdev->dev;
+
+	if (!list_empty(&fdev->device_list)) {
+		DRM_ERROR("fbdevdrm: cleaned up device is still enqueued "
+			  "in device list\n");
+	}
+
+	drm_dev_fini(dev);
+	dev->dev_private = NULL;
+}
+
+struct fbdevdrm_device* fbdevdrm_device_create(struct drm_driver *drv,
+					       struct fb_info *fb_info)
+{
+	struct fbdevdrm_device *fdev;
+	int ret;
+
+	fdev = devm_kzalloc(fb_info->dev, sizeof(*fdev), GFP_KERNEL);
+	if (!fdev)
+		return ERR_PTR(-ENOMEM);
+	ret = fbdevdrm_device_init(fdev, drv, fb_info);
+	if (ret < 0)
+		goto err_devm_kfree;
+	return fdev;
+
+err_devm_kfree:
+	devm_kfree(fb_info->dev, fdev);
+	return ERR_PTR(ret);
+}
+
+void fbdevdrm_device_destroy(struct fbdevdrm_device *fdev)
+{
+	struct device *dev = fdev->fb_info->dev;
+
+	fbdevdrm_device_cleanup(fdev);
+	devm_kfree(dev, fdev);
+}
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h
new file mode 100644
index 000000000000..85878f60bba4
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#ifndef FBDEVDRM_DEVICE_H
+#define FBDEVDRM_DEVICE_H
+
+#include <drm/drm_device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct drm_driver;
+struct fb_info;
+
+struct fbdevdrm_device {
+	struct drm_device dev;
+	struct fb_info *fb_info;
+
+	struct list_head device_list; /* entry in global device list */
+};
+
+static inline struct fbdevdrm_device* fbdevdrm_device_of_device_list(
+	struct list_head *device_list)
+{
+	return list_entry(device_list, struct fbdevdrm_device, device_list);
+}
+
+int fbdevdrm_device_init(struct fbdevdrm_device *fdev, struct drm_driver *drv,
+			 struct fb_info *fb_info);
+void fbdevdrm_device_cleanup(struct fbdevdrm_device *fdev);
+
+struct fbdevdrm_device* fbdevdrm_device_create(struct drm_driver *drv,
+					       struct fb_info *fb_info);
+void fbdevdrm_device_destroy(struct fbdevdrm_device *fdev);
+
+#endif
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
index dcb263b0c386..5be902094dc6 100644
--- a/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
@@ -10,8 +10,13 @@
  * stated exception.
  */
 
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+#include <linux/console.h> /* for console_{un/lock}() */
 #include <linux/fb.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include "fbdevdrm_device.h"
 
 /* DRM porting note: Here are some general information about the driver,
  * licensing and maintenance contact. If you're porting an fbdev driver
@@ -29,18 +34,156 @@
 #define DRIVER_MINOR		0
 #define DRIVER_PATCHLEVEL	1
 
+/*
+ * DRM driver
+ */
+
+static struct drm_driver fbdevdrm_drv = {
+	/* data fields */
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESCRIPTION,
+	.date = DRIVER_DATE
+};
+
+/* Device list */
+
+static DEFINE_MUTEX(device_list_mutex);
+static LIST_HEAD(device_list);
+
+static void device_list_add(struct fbdevdrm_device *fdev)
+{
+	mutex_lock(&device_list_mutex);
+	list_add(&fdev->device_list, &device_list);
+	mutex_unlock(&device_list_mutex);
+}
+
+static struct fbdevdrm_device* device_list_del(struct fbdevdrm_device *fdev)
+{
+	mutex_lock(&device_list_mutex);
+	list_del(&fdev->device_list);
+	mutex_unlock(&device_list_mutex);
+
+	return fdev;
+}
+
+static struct fbdevdrm_device* device_list_find_by_fb_info(
+	const struct fb_info *fb_info)
+{
+	struct list_head *pos;
+	struct fbdevdrm_device *fdev = NULL;
+
+	mutex_lock(&device_list_mutex);
+	list_for_each(pos, &device_list) {
+		struct fbdevdrm_device *pos_fdev +			fbdevdrm_device_of_device_list(pos);
+		if (pos_fdev->fb_info = fb_info) {
+			fdev = pos_fdev;
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&device_list_mutex);
+	return fdev;
+}
+
 /* Module entry points */
 
+static bool is_generic_driver(const struct fb_info *fb_info)
+{
+	/* DRM porting note: We don't want to bind to vga16fb, vesafb, or any
+	 * other generic fbdev driver. Usually, these drivers have limited
+	 * capabilitis. We only continue if the fix structure indicates a
+	 * hardware-specific drivers . This test will also sort out drivers
+	 * registered via DRM's fbdev emulation. If you're porting an fbdev
+	 * driver to DRM, you can remove this test. The module's PCI device
+	 * ids will contain this information.
+	 */
+	return !fb_info->fix.accel &&
+	       !!strcmp(fb_info->fix.id, "S3 Virge/DX");
+}
+
+static int on_fb_registered(struct fb_info *fb_info, void *data)
+{
+	struct fbdevdrm_device *fdev;
+	int ret;
+
+	if (is_generic_driver(fb_info)) {
+		DRM_ERROR("fbdevdrm: not binding to %s\n", fb_info->fix.id);
+		return 0;
+	}
+
+	fdev = fbdevdrm_device_create(&fbdevdrm_drv, fb_info);
+	if (IS_ERR(fdev))
+		return PTR_ERR(fdev);
+	device_list_add(fdev);
+
+	ret = drm_dev_register(&fdev->dev, 0);
+	if (ret)
+		goto err_device_list_del;
+
+	return 0;
+
+err_device_list_del:
+	device_list_del(fdev);
+	fbdevdrm_device_destroy(fdev);
+	return ret;
+}
+
+static int on_fb_unregistered(struct fb_info *fb_info, void *data)
+{
+	struct fbdevdrm_device *fdev;
+
+	fdev = device_list_find_by_fb_info(fb_info);
+	if (!fdev)
+		return 0;
+
+	device_list_del(fdev);
+	fbdevdrm_device_destroy(fdev);
+
+	return 0;
+}
+
 static int fb_client_notifier_call(struct notifier_block *nb,
 				   unsigned long action, void *data)
 {
+	static const char* const event_name[] = {
+#define EVENT_NAME(_ev) \
+	[_ev] = #_ev
+		EVENT_NAME(FB_EVENT_MODE_CHANGE),
+		EVENT_NAME(FB_EVENT_SUSPEND),
+		EVENT_NAME(FB_EVENT_RESUME),
+		EVENT_NAME(FB_EVENT_MODE_DELETE),
+		EVENT_NAME(FB_EVENT_FB_REGISTERED),
+		EVENT_NAME(FB_EVENT_FB_UNREGISTERED),
+		EVENT_NAME(FB_EVENT_GET_CONSOLE_MAP),
+		EVENT_NAME(FB_EVENT_SET_CONSOLE_MAP),
+		EVENT_NAME(FB_EVENT_BLANK),
+		EVENT_NAME(FB_EVENT_NEW_MODELIST),
+		EVENT_NAME(FB_EVENT_MODE_CHANGE_ALL),
+		EVENT_NAME(FB_EVENT_CONBLANK),
+		EVENT_NAME(FB_EVENT_GET_REQ),
+		EVENT_NAME(FB_EVENT_FB_UNBIND),
+		EVENT_NAME(FB_EVENT_REMAP_ALL_CONSOLE),
+		EVENT_NAME(FB_EARLY_EVENT_BLANK),
+		EVENT_NAME(FB_R_EARLY_EVENT_BLANK)
+#undef EVENT_NAME
+	};
+
 	static int (* const on_event[])(struct fb_info*, void*) = {
+		[FB_EVENT_FB_REGISTERED]   = on_fb_registered,
+		[FB_EVENT_FB_UNREGISTERED] = on_fb_unregistered
 	};
 
 	const struct fb_event *event = data;
 
-	if ((action >= ARRAY_SIZE(on_event)) || !on_event[action])
+	if ((action >= ARRAY_SIZE(on_event)) || !on_event[action]) {
+		DRM_ERROR("fbdevdrm: unhandled event %s\n",
+				event_name[action]);
 		return 0; /* event not handled by us */
+	}
 	return on_event[action](event->info, event->data);
 }
 
@@ -50,13 +193,39 @@ static struct notifier_block fb_client = {
 
 static int __init fbdevdrm_init(void)
 {
-	int ret;
+	int ret, i;
 
 	ret = fb_register_client(&fb_client);
 	if (ret < 0)
 		return ret;
 
+	/* There might already be registered FB devices. We go
+	 * through them manually to create a corresponding DRM
+	 * device. For the event notifier, all the locking is
+	 * performed by the fbdev framework. Here, we have to
+	 * do it by ourselves. */
+
+	console_lock();
+
+	for_each_registered_fb(i) {
+		struct fb_info *fb_info = registered_fb[i];
+		if (!lock_fb_info(fb_info)) {
+			ret = -ENODEV;
+			goto err_console_unlock;
+		}
+		ret = on_fb_registered(fb_info, NULL);
+		unlock_fb_info(fb_info);
+		if (ret < 0)
+			goto err_console_unlock;
+	}
+
+	console_unlock();
+
 	return 0;
+
+err_console_unlock:
+	console_unlock();
+	return ret;
 }
 
 static void __exit fbdevdrm_exit(void)
-- 
2.21.0

WARNING: multiple messages have this Message-ID (diff)
From: Thomas Zimmermann <tzimmermann@suse.de>
To: airlied@linux.ie, daniel@ffwll.ch, b.zolnierkie@samsung.com
Cc: linux-fbdev@vger.kernel.org,
	Thomas Zimmermann <tzimmermann@suse.de>,
	dri-devel@lists.freedesktop.org
Subject: [PATCH 02/11] drm/fbdevdrm: Add fbdevdrm device
Date: Tue, 26 Mar 2019 10:17:35 +0100	[thread overview]
Message-ID: <20190326091744.11542-3-tzimmermann@suse.de> (raw)
In-Reply-To: <20190326091744.11542-1-tzimmermann@suse.de>

There's an fbdevdrm device for each supported fbdev device. The fbdevdrm
driver listens for fb events, and creates and destroys fbdevdrm devices
accordingly.

Only hardware-specific fbdev drivers are supported. Generic drivers, such
as vga16fb or vesafb are not handled. DRM-based fbdev drivers are also not
supported. This prevents the situation where a DRM drivers enables
framebuffer emulation and fbdevdrm creates a second DRM device for the
same hardware.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/fbdevdrm/Makefile          |   3 +-
 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c |  79 ++++++++++
 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h |  44 ++++++
 drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c    | 173 ++++++++++++++++++++-
 4 files changed, 296 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h

diff --git a/drivers/gpu/drm/fbdevdrm/Makefile b/drivers/gpu/drm/fbdevdrm/Makefile
index 65e6b43cf682..750940d38509 100644
--- a/drivers/gpu/drm/fbdevdrm/Makefile
+++ b/drivers/gpu/drm/fbdevdrm/Makefile
@@ -1,4 +1,5 @@
 ccflags-y = -Iinclude/drm
-fbdevdrm-y := fbdevdrm_drv.o
+fbdevdrm-y := fbdevdrm_device.o \
+	      fbdevdrm_drv.o
 
 obj-$(CONFIG_DRM_FBDEVDRM) += fbdevdrm.o
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
new file mode 100644
index 000000000000..0abf41cf05bb
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#include "fbdevdrm_device.h"
+#include <drm/drm_drv.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_print.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+/*
+ * struct fbdrmdev_device
+ */
+
+int fbdevdrm_device_init(struct fbdevdrm_device *fdev, struct drm_driver *drv,
+			 struct fb_info *fb_info)
+{
+	int ret;
+
+	ret = drm_dev_init(&fdev->dev, drv, fb_info->device);
+	if (ret)
+		return ret;
+	fdev->dev.dev_private = fdev;
+	fdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+	fdev->fb_info = fb_info;
+
+	INIT_LIST_HEAD(&fdev->device_list);
+
+	return 0;
+}
+
+void fbdevdrm_device_cleanup(struct fbdevdrm_device *fdev)
+{
+	struct drm_device *dev = &fdev->dev;
+
+	if (!list_empty(&fdev->device_list)) {
+		DRM_ERROR("fbdevdrm: cleaned up device is still enqueued "
+			  "in device list\n");
+	}
+
+	drm_dev_fini(dev);
+	dev->dev_private = NULL;
+}
+
+struct fbdevdrm_device* fbdevdrm_device_create(struct drm_driver *drv,
+					       struct fb_info *fb_info)
+{
+	struct fbdevdrm_device *fdev;
+	int ret;
+
+	fdev = devm_kzalloc(fb_info->dev, sizeof(*fdev), GFP_KERNEL);
+	if (!fdev)
+		return ERR_PTR(-ENOMEM);
+	ret = fbdevdrm_device_init(fdev, drv, fb_info);
+	if (ret < 0)
+		goto err_devm_kfree;
+	return fdev;
+
+err_devm_kfree:
+	devm_kfree(fb_info->dev, fdev);
+	return ERR_PTR(ret);
+}
+
+void fbdevdrm_device_destroy(struct fbdevdrm_device *fdev)
+{
+	struct device *dev = fdev->fb_info->dev;
+
+	fbdevdrm_device_cleanup(fdev);
+	devm_kfree(dev, fdev);
+}
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h
new file mode 100644
index 000000000000..85878f60bba4
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_device.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#ifndef FBDEVDRM_DEVICE_H
+#define FBDEVDRM_DEVICE_H
+
+#include <drm/drm_device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct drm_driver;
+struct fb_info;
+
+struct fbdevdrm_device {
+	struct drm_device dev;
+	struct fb_info *fb_info;
+
+	struct list_head device_list; /* entry in global device list */
+};
+
+static inline struct fbdevdrm_device* fbdevdrm_device_of_device_list(
+	struct list_head *device_list)
+{
+	return list_entry(device_list, struct fbdevdrm_device, device_list);
+}
+
+int fbdevdrm_device_init(struct fbdevdrm_device *fdev, struct drm_driver *drv,
+			 struct fb_info *fb_info);
+void fbdevdrm_device_cleanup(struct fbdevdrm_device *fdev);
+
+struct fbdevdrm_device* fbdevdrm_device_create(struct drm_driver *drv,
+					       struct fb_info *fb_info);
+void fbdevdrm_device_destroy(struct fbdevdrm_device *fdev);
+
+#endif
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
index dcb263b0c386..5be902094dc6 100644
--- a/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_drv.c
@@ -10,8 +10,13 @@
  * stated exception.
  */
 
+#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
+#include <linux/console.h> /* for console_{un/lock}() */
 #include <linux/fb.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include "fbdevdrm_device.h"
 
 /* DRM porting note: Here are some general information about the driver,
  * licensing and maintenance contact. If you're porting an fbdev driver
@@ -29,18 +34,156 @@
 #define DRIVER_MINOR		0
 #define DRIVER_PATCHLEVEL	1
 
+/*
+ * DRM driver
+ */
+
+static struct drm_driver fbdevdrm_drv = {
+	/* data fields */
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESCRIPTION,
+	.date = DRIVER_DATE
+};
+
+/* Device list */
+
+static DEFINE_MUTEX(device_list_mutex);
+static LIST_HEAD(device_list);
+
+static void device_list_add(struct fbdevdrm_device *fdev)
+{
+	mutex_lock(&device_list_mutex);
+	list_add(&fdev->device_list, &device_list);
+	mutex_unlock(&device_list_mutex);
+}
+
+static struct fbdevdrm_device* device_list_del(struct fbdevdrm_device *fdev)
+{
+	mutex_lock(&device_list_mutex);
+	list_del(&fdev->device_list);
+	mutex_unlock(&device_list_mutex);
+
+	return fdev;
+}
+
+static struct fbdevdrm_device* device_list_find_by_fb_info(
+	const struct fb_info *fb_info)
+{
+	struct list_head *pos;
+	struct fbdevdrm_device *fdev = NULL;
+
+	mutex_lock(&device_list_mutex);
+	list_for_each(pos, &device_list) {
+		struct fbdevdrm_device *pos_fdev =
+			fbdevdrm_device_of_device_list(pos);
+		if (pos_fdev->fb_info == fb_info) {
+			fdev = pos_fdev;
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&device_list_mutex);
+	return fdev;
+}
+
 /* Module entry points */
 
+static bool is_generic_driver(const struct fb_info *fb_info)
+{
+	/* DRM porting note: We don't want to bind to vga16fb, vesafb, or any
+	 * other generic fbdev driver. Usually, these drivers have limited
+	 * capabilitis. We only continue if the fix structure indicates a
+	 * hardware-specific drivers . This test will also sort out drivers
+	 * registered via DRM's fbdev emulation. If you're porting an fbdev
+	 * driver to DRM, you can remove this test. The module's PCI device
+	 * ids will contain this information.
+	 */
+	return !fb_info->fix.accel &&
+	       !!strcmp(fb_info->fix.id, "S3 Virge/DX");
+}
+
+static int on_fb_registered(struct fb_info *fb_info, void *data)
+{
+	struct fbdevdrm_device *fdev;
+	int ret;
+
+	if (is_generic_driver(fb_info)) {
+		DRM_ERROR("fbdevdrm: not binding to %s\n", fb_info->fix.id);
+		return 0;
+	}
+
+	fdev = fbdevdrm_device_create(&fbdevdrm_drv, fb_info);
+	if (IS_ERR(fdev))
+		return PTR_ERR(fdev);
+	device_list_add(fdev);
+
+	ret = drm_dev_register(&fdev->dev, 0);
+	if (ret)
+		goto err_device_list_del;
+
+	return 0;
+
+err_device_list_del:
+	device_list_del(fdev);
+	fbdevdrm_device_destroy(fdev);
+	return ret;
+}
+
+static int on_fb_unregistered(struct fb_info *fb_info, void *data)
+{
+	struct fbdevdrm_device *fdev;
+
+	fdev = device_list_find_by_fb_info(fb_info);
+	if (!fdev)
+		return 0;
+
+	device_list_del(fdev);
+	fbdevdrm_device_destroy(fdev);
+
+	return 0;
+}
+
 static int fb_client_notifier_call(struct notifier_block *nb,
 				   unsigned long action, void *data)
 {
+	static const char* const event_name[] = {
+#define EVENT_NAME(_ev) \
+	[_ev] = #_ev
+		EVENT_NAME(FB_EVENT_MODE_CHANGE),
+		EVENT_NAME(FB_EVENT_SUSPEND),
+		EVENT_NAME(FB_EVENT_RESUME),
+		EVENT_NAME(FB_EVENT_MODE_DELETE),
+		EVENT_NAME(FB_EVENT_FB_REGISTERED),
+		EVENT_NAME(FB_EVENT_FB_UNREGISTERED),
+		EVENT_NAME(FB_EVENT_GET_CONSOLE_MAP),
+		EVENT_NAME(FB_EVENT_SET_CONSOLE_MAP),
+		EVENT_NAME(FB_EVENT_BLANK),
+		EVENT_NAME(FB_EVENT_NEW_MODELIST),
+		EVENT_NAME(FB_EVENT_MODE_CHANGE_ALL),
+		EVENT_NAME(FB_EVENT_CONBLANK),
+		EVENT_NAME(FB_EVENT_GET_REQ),
+		EVENT_NAME(FB_EVENT_FB_UNBIND),
+		EVENT_NAME(FB_EVENT_REMAP_ALL_CONSOLE),
+		EVENT_NAME(FB_EARLY_EVENT_BLANK),
+		EVENT_NAME(FB_R_EARLY_EVENT_BLANK)
+#undef EVENT_NAME
+	};
+
 	static int (* const on_event[])(struct fb_info*, void*) = {
+		[FB_EVENT_FB_REGISTERED]   = on_fb_registered,
+		[FB_EVENT_FB_UNREGISTERED] = on_fb_unregistered
 	};
 
 	const struct fb_event *event = data;
 
-	if ((action >= ARRAY_SIZE(on_event)) || !on_event[action])
+	if ((action >= ARRAY_SIZE(on_event)) || !on_event[action]) {
+		DRM_ERROR("fbdevdrm: unhandled event %s\n",
+				event_name[action]);
 		return 0; /* event not handled by us */
+	}
 	return on_event[action](event->info, event->data);
 }
 
@@ -50,13 +193,39 @@ static struct notifier_block fb_client = {
 
 static int __init fbdevdrm_init(void)
 {
-	int ret;
+	int ret, i;
 
 	ret = fb_register_client(&fb_client);
 	if (ret < 0)
 		return ret;
 
+	/* There might already be registered FB devices. We go
+	 * through them manually to create a corresponding DRM
+	 * device. For the event notifier, all the locking is
+	 * performed by the fbdev framework. Here, we have to
+	 * do it by ourselves. */
+
+	console_lock();
+
+	for_each_registered_fb(i) {
+		struct fb_info *fb_info = registered_fb[i];
+		if (!lock_fb_info(fb_info)) {
+			ret = -ENODEV;
+			goto err_console_unlock;
+		}
+		ret = on_fb_registered(fb_info, NULL);
+		unlock_fb_info(fb_info);
+		if (ret < 0)
+			goto err_console_unlock;
+	}
+
+	console_unlock();
+
 	return 0;
+
+err_console_unlock:
+	console_unlock();
+	return ret;
 }
 
 static void __exit fbdevdrm_exit(void)
-- 
2.21.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2019-03-26  9:17 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-26  9:17 [RFC][PATCH 00/11] DRM driver for fbdev devices Thomas Zimmermann
2019-03-26  9:17 ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 01/11] drm/fbdevdrm: Add driver skeleton Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` Thomas Zimmermann [this message]
2019-03-26  9:17   ` [PATCH 02/11] drm/fbdevdrm: Add fbdevdrm device Thomas Zimmermann
2019-03-26 16:03   ` Adam Jackson
2019-03-26 16:03     ` Adam Jackson
2019-03-27  7:55     ` Thomas Zimmermann
2019-03-27  7:55       ` Thomas Zimmermann
2019-03-27  8:03       ` Daniel Vetter
2019-03-27  8:03         ` Daniel Vetter
2019-03-26  9:17 ` [PATCH 03/11] drm/fbdevdrm: Add memory management Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 04/11] drm/fbdevdrm: Add file operations Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 05/11] drm/fbdevdrm: Add GEM and dumb interfaces Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 06/11] drm/fbdevdrm: Add modesetting infrastructure Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 07/11] drm/fbdevdrm: Add DRM <-> fbdev pixel-format conversion Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26 16:29   ` Ville Syrjälä
2019-03-26 16:29     ` Ville Syrjälä
2019-03-27  8:28     ` Thomas Zimmermann
2019-03-27  8:28       ` Thomas Zimmermann
2019-03-27 10:00       ` Ville Syrjälä
2019-03-27 10:00         ` Ville Syrjälä
2019-03-26  9:17 ` [PATCH 08/11] drm/fbdevdrm: Add mode conversion DRM <-> fbdev Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 09/11] drm/fbdevdrm: Add primary plane Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26 13:33   ` Mathieu Malaterre
2019-03-26 13:33     ` Mathieu Malaterre
2019-03-26 13:57     ` Thomas Zimmermann
2019-03-26 13:57       ` Thomas Zimmermann
2019-03-27  9:37     ` Thomas Zimmermann
2019-03-27  9:37       ` Thomas Zimmermann
2019-04-02  7:08       ` Mathieu Malaterre
2019-04-02  7:08         ` Mathieu Malaterre
2019-03-26  9:17 ` [PATCH 10/11] drm/fbdevdrm: Add CRTC Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26  9:17 ` [PATCH 11/11] drm/fbdevdrm: Detect and validate display modes Thomas Zimmermann
2019-03-26  9:17   ` Thomas Zimmermann
2019-03-26 16:47   ` Ville Syrjälä
2019-03-26 16:47     ` Ville Syrjälä
2019-03-26 18:20     ` Daniel Vetter
2019-03-26 18:20       ` Daniel Vetter
2019-03-27  8:31     ` Thomas Zimmermann
2019-03-27  8:31       ` Thomas Zimmermann
2019-03-26 14:53 ` [RFC][PATCH 00/11] DRM driver for fbdev devices Daniel Vetter
2019-03-26 14:53   ` Daniel Vetter
2019-03-27  9:10   ` Thomas Zimmermann
2019-03-27  9:10     ` Thomas Zimmermann
2019-03-27  9:41     ` Daniel Vetter
2019-03-27  9:41       ` Daniel Vetter
2019-03-27  9:55       ` Michel Dänzer
2019-03-27  9:55         ` Michel Dänzer
2019-03-27 10:58         ` Daniel Vetter
2019-03-27 10:58           ` Daniel Vetter
2019-03-27 14:46       ` Thomas Zimmermann
2019-03-27 14:46         ` Thomas Zimmermann
2019-03-27 17:05         ` Daniel Vetter
2019-03-27 17:05           ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190326091744.11542-3-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=airlied@linux.ie \
    --cc=b.zolnierkie@samsung.com \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-fbdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.