Skip to contentSkip to conversation

enhancing the kernel's graphics subsystem

RFC In review Jesse Barnes 20 participants 100 messages May 17, 2007 – May 30, 2007

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

Patches at http://www.kernel.org/pub/linux/kernel/people/jbarnes/patches
drm-modesetting-core.patch
drm-modesetting-i915.patch
console-unregister.patch
(Sorry the first two are slightly too big for lkml; they're against the DRM tree at git://git.freedesktop.org/git/mesa/drm.)

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

In the interest of getting some early feedback, I thought I'd post a description of how we've structured things so far, along with some of the early code, to get some feedback on the direction.

Why in the kernel?

There are several reasons to pull modesetting and proper multihead support into the kernel:
- suspend/resume
- debugging (e.g. panic)
- non-X uses
- more reliable VT switch
Each of the above is covered in more detail below.

Suspend/resume

Currently, the kernel has to rely on an external application (X, vbetool, etc.), or worse, ACPI, to reset video devices to the proper state after resume. If one of these systems has trouble or crashes during or shortly after resume, the system will become unusable, with little indication as to why (see Debugging below). Putting code into the kernel to perform low level modesetting (i.e. without video BIOS support) will allow the kernel to resume to the correct mode automatically and more quickly than would be possible otherwise.

Debugging

As mentioned above, if something goes wrong with modesetting during resume, the user has very little indication of where things went wrong. Likewise, if a panic or oops occurs while an application like X is running, the user will experience a hard hang, rather than the much more pleasant "blue penguin of death" (to be coded). With kernel modesetting support, the kernel should be able to display panic and oops messages directly on the console, even if a graphical application is running, since it would have awareness of the current mode, display depth, pitch, and other variables needed to display output. Another possibility is multihead debugging: one display could run the user's applications (i.e. a "normal" display) while a secondary display could run a system level debugger, allowing the user to stop the machine, investigate memory, step through programs, etc. (admittedly this is somewhat far fetched).

Non-X uses

As it stands, non-X based applications wanting to use video devices have two options: either take over the hardware themselves or use the existing kernel fb layer. The former is obviously a tall order given the complexity of current graphics devices, while the latter isn't featureful enough to expose multiple outputs, perform per-device locking so that multiple clients can share the device, etc. A kernel based modsetting and multihead API would make developing such applications much easier.

VT switch

Currently, the kernel relies on an external program to restore the graphics state when a VT switch occurs. This doesn't always work, with similar results to the suspend/resume case: an apparently hung or unusable machine. Of course, the kernel can't unconditionally preempt the graphics device to set a new mode, but having modesetting in the kernel will give it a much better chance of coordinating with the DRM command dispatch code to find a good time to set a new mode.

Interfaces

With the above patches, the kernel DRM layer manages the output devices, available modes, and calls into the low level DRM drivers to set modes and probe outputs devices for attached displays, much like the X server's internal RandR 1.2 APIs. It also provides userspace with an interface to these functions (Jakob based these APIs on the X server's Randr extension, but there are differences).

DRM/FB cooperation

Another major factor to consider when enhancing modesetting in the kernel is DRM and FB cooperation. Currently, FB isn't aware of DRM drivers, and DRM is only minimally aware of FB (such that it can bind to PCI devices even after FB drivers have already done so). As a result, any modesetting done by either layer results in memory allocation that may not be honored by the other side (and/or the X server, which has its own idea of how memory is being used). To properly address interoperability, both the FB and DRM layers need to share a common memory manager, common suspend/resume code, and common modesetting code. In addition, applications must use these layers in some way to avoid conflicts (e.g. X should call into the DRM or FB layers to do memory allocation).

What about the FB layer?

Today, the FB layer is really only well aware of a single head, and doesn't do full EDID parsing, therefore its knowledge of available modes is limited. On the plus side, it's able to fetch EDID data where possible and generate modes using the VESA CVT specification.

In kernel APIs

The kernel APIs are broken up into several parts, as documented in drm_crtc.h. There are two sets of callbacks that a driver must implement to fully support the model, one for the driver's CRTC(s), and one for its supported outputs.

Userland APIs

DRM_IOCTL_MODE_GETRESOURCES - get number of CRTCs, FBs DRM_IOCTL_MODE_GETCRTC - get info about a given CRTC DRM_IOCTL_MODE_GETOUTPUT - get info about a given output DRM_IOCTL_MODE_SETCRTC - set CRTC parameters DRM_IOCTL_MODE_ADDFB - add a new FB object DRM_IOCTL_MODE_RMFB - remove an FB object DRM_IOCTL_MODE_GETFB - get info about an FB object

Notes on the current codebase

The current codebase is still incomplete in many ways: locking needs to be (re-)added around our various list manipulation paths, we need better initial configuration logic, only the Intel driver has any support (and it's still missing suspend/resume and accelerated FB functions), we need to check modes against monitor limitations (which come from EDID or the user), CVT and GTF based mode generation still isn't used by the DRM modesetting code, and much more. I'm hoping that by posting this now, we can get some ideas about what requirements other people have for graphics on Linux so we can prioritize our work.

And of course, large chunks of this code came from X.Org's modesetting and Intel driver code, but it should all be marked with the proper copyrights and licenses if it wasn't written from scratch.

Comments, questions, suggestions?

Thanks,
Jesse

#1 lore raw

PATCH 1/3 allow console unregistration

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Jesse

drivers/video/fbmem.c +2 -0
@@ -1349,6 +1349,8 @@
 	if (!registered_fb[i])
 		return -EINVAL;
 
+	event.info = fb_info;
+	fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
 	if (fb_info->pixmap.addr &&
 	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
include/linux/fb.h +2 -0
@@ -525,6 +525,8 @@
 #define FB_EVENT_MODE_CHANGE_ALL	0x0B
 /*	A software display blank change occured */
 #define FB_EVENT_CONBLANK               0x0C
+/*      Unbind from the console if possible */
+#define FB_EVENT_FB_UNBIND              0x0E
 
 struct fb_event {
 	struct fb_info *info;
include/linux/console.h +1 -0
@@ -64,6 +64,7 @@
 extern const struct consw newport_con;	/* SGI Newport console  */
 extern const struct consw prom_con;	/* SPARC PROM console */
 
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt);
 int con_is_bound(const struct consw *csw);
 int register_con_driver(const struct consw *csw, int first, int last);
 int unregister_con_driver(const struct consw *csw);
drivers/video/console/fbcon.c +16 -1
@@ -563,8 +563,10 @@
 	for (i = first_fb_vc; i <= last_fb_vc; i++)
 		con2fb_map[i] = info_idx;
 
+	printk(KERN_ERR "calling take_over_console, return value: ");
 	err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
 				fbcon_is_default);
+	printk(KERN_ERR "%d\n", err);
 
 	if (err) {
 		for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -2896,6 +2898,13 @@
 	return found;
 }
 
+static int fbcon_fb_unbind(int idx)
+{
+	unbind_con_driver(&fb_con, 0, MAX_NR_CONSOLES - 1, 0);
+
+	return 0;
+}
+
 static int fbcon_fb_unregistered(int idx)
 {
 	int i;
@@ -2933,6 +2942,7 @@
 {
 	int ret = 0, i;
 
+	printk(KERN_ERR "fbcon registration called\n");
 	if (info_idx == -1) {
 		for (i = first_fb_vc; i <= last_fb_vc; i++) {
 			if (con2fb_map_boot[i] == idx) {
@@ -2941,8 +2951,10 @@
 			}
 		}
 
-		if (info_idx != -1)
+		if (info_idx != -1) {
+			printk(KERN_ERR "fb taking over console\n");
 			ret = fbcon_takeover(1);
+		}
 	} else {
 		for (i = first_fb_vc; i <= last_fb_vc; i++) {
 			if (con2fb_map_boot[i] == idx &&
@@ -3036,6 +3048,9 @@
 		mode = event->data;
 		ret = fbcon_mode_deleted(info, mode);
 		break;
+	case FB_EVENT_FB_UNBIND:
+		ret = fbcon_fb_unbind(info->node);
+		break;
 	case FB_EVENT_FB_REGISTERED:
 		ret = fbcon_fb_registered(info->node);
 		break;
drivers/char/vt.c +19 -2
@@ -2832,8 +2832,24 @@
 	return retval;
 }
 
-static int unbind_con_driver(const struct consw *csw, int first, int last,
-			     int deflt)
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ * 
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
 {
 	struct module *owner = csw->owner;
 	const struct consw *defcsw = NULL;
@@ -2918,6 +2934,7 @@
 	return retval;
 
 }
+EXPORT_SYMBOL(unbind_con_driver);
 
 static int vt_bind(struct con_driver *con)
 {
#2 lore raw

Re: [PATCH 1/3] allow console unregistration

Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

And before someone complains, here's the diffstat:

 drivers/char/vt.c             |   21 +++++++++++++++++++--
 drivers/video/console/fbcon.c |   17 ++++++++++++++++-
 drivers/video/fbmem.c         |    2 ++
 include/linux/console.h       |    1 +
 include/linux/fb.h            |    2 ++
 5 files changed, 40 insertions(+), 3 deletions(-)
#3 lore raw

Re: [PATCH 1/3] allow console unregistration

In reply to Jesse Barnes
Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Sorry, I was busy and got sidetracked so I wasn't able to work on this for 2 weeks. Yes, this should work for now, at least for debugging purposes. I'll work on refining on fbcon side, hopefully for 2.6.22-2.6.23 time frame.

Tony

#4 lore raw

Re: [PATCH 1/3] allow console unregistration

Quoted 10 lines · Antonino A. Daplas
Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Quoted 4 lines

Sorry, I was busy and got sidetracked so I wasn't able to work on this for 2 weeks. Yes, this should work for now, at least for debugging purposes. I'll work on refining on fbcon side, hopefully for 2.6.22-2.6.23 time frame.

No problem, I don't expect the rest of the code to be ready for awhile... This patch should be pretty close (modulo debugging statements and other bogons) to what we discussed earlier. I think the main change that's needed is to only unregister the specific console that was registered, rather than all of them.

Thanks,
Jesse

#5 lore raw

PATCH 1/2 allow console unregistration

In reply to Antonino A. Daplas
Quoted 10 lines · Antonino A. Daplas
Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Quoted 4 lines

Sorry, I was busy and got sidetracked so I wasn't able to work on this for 2 weeks. Yes, this should work for now, at least for debugging purposes. I'll work on refining on fbcon side, hopefully for 2.6.22-2.6.23 time frame.

Btw, here's an updated console unregister patchset with signoff in the off chance you like it right away. :)

When rmmod'd, some drivers might like to unregister the console they have registered (e.g. the fbcon driver), so export unbind_con_driver. It properly cleans up console references and takes care of switching to one of the other registered drivers as needed.

drivers/char/vt.c +19 -2
diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/char/vt.c linux-2.6.22-rc2-modesetting/drivers/char/vt.c
@@ -2981,8 +2981,24 @@ static int con_is_graphics(const struct 
 	return retval;
 }
 
-static int unbind_con_driver(const struct consw *csw, int first, int last,
-			     int deflt)
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ * 
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
 {
 	struct module *owner = csw->owner;
 	const struct consw *defcsw = NULL;
@@ -3067,6 +3083,7 @@ err:
 	return retval;
 
 }
+EXPORT_SYMBOL(unbind_con_driver);
 
 static int vt_bind(struct con_driver *con)
 {
include/linux/console.h +1 -0
diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/include/linux/console.h linux-2.6.22-rc2-modesetting/include/linux/console.h
@@ -64,6 +64,7 @@ extern const struct consw vga_con;	/* VG
 extern const struct consw newport_con;	/* SGI Newport console  */
 extern const struct consw prom_con;	/* SPARC PROM console */
 
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt);
 int con_is_bound(const struct consw *csw);
 int register_con_driver(const struct consw *csw, int first, int last);
 int unregister_con_driver(const struct consw *csw);
#6 lore raw

Re: [PATCH 1/2] allow console unregistration

Quoted 16 lines · Jesse Barnes
Quoted 10 lines · Antonino A. Daplas
Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Quoted 4 lines

Sorry, I was busy and got sidetracked so I wasn't able to work on this for 2 weeks. Yes, this should work for now, at least for debugging purposes. I'll work on refining on fbcon side, hopefully for 2.6.22-2.6.23 time frame.

Quoted 8 lines

Btw, here's an updated console unregister patchset with signoff in the off chance you like it right away. :)

When rmmod'd, some drivers might like to unregister the console they have registered (e.g. the fbcon driver), so export unbind_con_driver. It properly cleans up console references and takes care of switching to one of the other registered drivers as needed.

I'm working on something that will need these functions (unbind/bind_con_driver) to be exposed, so I'm fine with this.

Tony

#7 lore raw

PATCH 2/2 make fbcon unregister when unloaded

In reply to Antonino A. Daplas
Quoted 10 lines · Antonino A. Daplas
Quoted 8 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Quoted 4 lines

Sorry, I was busy and got sidetracked so I wasn't able to work on this for 2 weeks. Yes, this should work for now, at least for debugging purposes. I'll work on refining on fbcon side, hopefully for 2.6.22-2.6.23 time frame.

When unloaded, the fbcon driver should unregister itself from the VT subsystem using unbind_con_driver. This patch makes it use the newly exported function to do just that.

drivers/video/console/fbcon.c +18 -0
diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/video/console/fbcon.c linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c
@@ -2937,6 +2937,21 @@ static int fbcon_mode_deleted(struct fb_
 	return found;
 }
 
+static int fbcon_fb_unbind(int idx)
+{
+	int i;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                /* Assure we do not unbind other drivers */
+                if (idx == con2fb_map[i])
+                        /* can be optimize to minimize multiple calls to
+			   unbind_con_driver() */
+                        unbind_con_driver(&fb_con, i, i, 0); 
+        }
+
+	return 0;
+}
+
 static int fbcon_fb_unregistered(int idx)
 {
 	int i;
@@ -3114,6 +3129,9 @@ static int fbcon_event_notify(struct not
 		mode = event->data;
 		ret = fbcon_mode_deleted(info, mode);
 		break;
+	case FB_EVENT_FB_UNBIND:
+		ret = fbcon_fb_unbind(info->node);
+		break;
 	case FB_EVENT_FB_REGISTERED:
 		ret = fbcon_fb_registered(info->node);
 		break;
drivers/video/fbmem.c +2 -0
diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/video/fbmem.c linux-2.6.22-rc2-modesetting/drivers/video/fbmem.c
@@ -1400,6 +1400,8 @@ unregister_framebuffer(struct fb_info *f
 	if (!registered_fb[i])
 		return -EINVAL;
 
+	event.info = fb_info;
+	fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
 	if (fb_info->pixmap.addr &&
 	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
include/linux/fb.h +3 -0
diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/include/linux/fb.h linux-2.6.22-rc2-modesetting/include/linux/fb.h
@@ -529,6 +529,9 @@ struct fb_cursor_user {
 #define FB_EVENT_CONBLANK               0x0C
 /*      Get drawing requirements        */
 #define FB_EVENT_GET_REQ                0x0D
+/*      Unbind from the console if possible */
+#define FB_EVENT_FB_UNBIND              0x0E
+
 
 struct fb_event {
 	struct fb_info *info;
#8 lore raw

Re: [PATCH 2/2] make fbcon unregister when unloaded

Quoted 12 lines · On Tue, 22 May 2007 14:44:52 -0700 Jesse Barnes wrote:

When unloaded, the fbcon driver should unregister itself from the VT subsystem using unbind_con_driver. This patch makes it use the newly exported function to do just that.

diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/video/console/fbcon.c linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c

drivers/video/console/fbcon.c +0 -0
@@ -2937,6 +2937,21 @@ static int fbcon_mode_deleted(struct fb_
 	return found;
 }

drivers/video/console/fbcon.c static int fbcon_mode_deleted(struct fb_ · line 2948

Quoted 10 lines
drivers/video/console/fbcon.c +9 -0
 
+static int fbcon_fb_unbind(int idx)
+{
+	int i;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                /* Assure we do not unbind other drivers */
+                if (idx == con2fb_map[i])
+                        /* can be optimize to minimize multiple calls to
+			   unbind_con_driver() */
			/*
			 * can be optimized to minimize multiple calls
			 * to unbind_con_driver()
			 */

drivers/video/console/fbcon.c static int fbcon_mode_deleted(struct fb_ · line 2953

Quoted 5 lines
drivers/video/console/fbcon.c +5 -0
+                        unbind_con_driver(&fb_con, i, i, 0); 
+        }
+
+	return 0;
+}

Lots of whitespace mangling there (mostly spaces instead of tabs).

drivers/video/console/fbcon.c static int fbcon_mode_deleted(struct fb_ · line 2957

Quoted 4 lines
drivers/video/console/fbcon.c +1 -0
+
 static int fbcon_fb_unregistered(int idx)
 {
 	int i;

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

#9 lore raw

Re: [PATCH 2/2] make fbcon unregister when unloaded

Quoted 32 lines · Randy Dunlap
Quoted 24 lines · On Tue, 22 May 2007 14:44:52 -0700 Jesse Barnes wrote:

When unloaded, the fbcon driver should unregister itself from the VT subsystem using unbind_con_driver. This patch makes it use the newly exported function to do just that.

diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/video/console/fbcon.c linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c ---
linux-2.6.22-rc2/drivers/video/console/fbcon.c 2007-05-18
21:06:17.000000000 -0700 +++
linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c 2007-05-
22 14:26:20.000000000 -0700 @@ -2937,6 +2937,21 @@ static int fbcon_mode_deleted(struct fb_ return found;
}

drivers/video/console/fbcon.c +8 -0
+static int fbcon_fb_unbind(int idx)
+{
+	int i;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                /* Assure we do not unbind other drivers */
+                if (idx == con2fb_map[i])
+                        /* can be optimize to minimize multiple
Quoted 1 line

calls to + unbind_con_driver() */

			/*
			 * can be optimized to minimize multiple calls
			 * to unbind_con_driver()
			 */
Quoted 7 lines

drivers/video/console/fbcon.c static int fbcon_mode_deleted(struct fb_ · line 2953

Quoted 5 lines
drivers/video/console/fbcon.c +5 -0
+                        unbind_con_driver(&fb_con, i, i, 0);
+        }
+
+	return 0;
+}

Lots of whitespace mangling there (mostly spaces instead of tabs).

Oops, thanks for looking. Somehow my emacs configuration broke and I don't see this as readily as I used to. If Antonio is ok with the patch otherwise, I'll respin it with the cleanups.

Thanks,
Jesse

#10 lore raw

Re: [PATCH 2/2] make fbcon unregister when unloaded

Quoted 41 lines · Jesse Barnes
Quoted 32 lines · Randy Dunlap
Quoted 24 lines · On Tue, 22 May 2007 14:44:52 -0700 Jesse Barnes wrote:

When unloaded, the fbcon driver should unregister itself from the VT subsystem using unbind_con_driver. This patch makes it use the newly exported function to do just that.

diff -Napur -X /home/jbarnes/dontdiff --exclude=Makefile linux-2.6.22-rc2/drivers/video/console/fbcon.c linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c ---
linux-2.6.22-rc2/drivers/video/console/fbcon.c 2007-05-18
21:06:17.000000000 -0700 +++
linux-2.6.22-rc2-modesetting/drivers/video/console/fbcon.c 2007-05-
22 14:26:20.000000000 -0700 @@ -2937,6 +2937,21 @@ static int fbcon_mode_deleted(struct fb_ return found;
}

drivers/video/console/fbcon.c +8 -0
+static int fbcon_fb_unbind(int idx)
+{
+	int i;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                /* Assure we do not unbind other drivers */
+                if (idx == con2fb_map[i])
+                        /* can be optimize to minimize multiple
Quoted 1 line

calls to + unbind_con_driver() */

			/*
			 * can be optimized to minimize multiple calls
			 * to unbind_con_driver()
			 */
Quoted 7 lines

drivers/video/console/fbcon.c static int fbcon_mode_deleted(struct fb_ · line 2953

Quoted 5 lines
drivers/video/console/fbcon.c +5 -0
+                        unbind_con_driver(&fb_con, i, i, 0);
+        }
+
+	return 0;
+}

Lots of whitespace mangling there (mostly spaces instead of tabs).

Quoted 3 lines

Oops, thanks for looking. Somehow my emacs configuration broke and I don't see this as readily as I used to. If Antonio is ok with the patch otherwise, I'll respin it with the cleanups.

This should be a lot safer than the previous patch. This is fine as long as only a single driver is driving the console. For multiple drivers, it will need the change that I promised weeks ago :-). (And I will work on it soon).

Tony

#11 lore raw

Re: [PATCH 1/3] allow console unregistration

In reply to Jesse Barnes
Quoted 9 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Jesse,

I already implemented (and tested) selective framebuffer/console unregistration in my tree using your patch as a base. I'll send this patch to akpm soon.

Geert,

Is this something that you might need for ps3fb? It should address 2 of your concerns. The only thing is that you will need CONFIG_VT_HW_CONSOLE_BINDING=y. You can default this to 'y' in your platform, or select it.

Tony

#12 lore raw

Re: [PATCH 1/3] allow console unregistration

Hi Tony,

Quoted 17 lines · Antonino A. Daplas
Quoted 9 lines · Jesse Barnes

Randy just informed me that the patch limits are bigger now, so here are the actual patches.

This patch allows for proper console unregistration via the VT layer, and updates the FB layer to use it. This makes debugging new console drivers much easier, since you can properly clean them up before unloading. Antonio already checked it out (and suggested a tweak for the fbcon side) so I think it's on its way already via the FB tree.

Jesse,

I already implemented (and tested) selective framebuffer/console unregistration in my tree using your patch as a base. I'll send this patch to akpm soon.

Quoted 6 lines

Geert,

Is this something that you might need for ps3fb? It should address 2 of your concerns. The only thing is that you will need CONFIG_VT_HW_CONSOLE_BINDING=y. You can default this to 'y' in your platform, or select it.

I was going to look at Jesse's patch, but it didn't happen yet. So yes, I'm definitely interested in your patch! Can you please send it to linux-fbdev-devel already?

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- Sony Network and Software Technology Center Europe (NSCE) [email protected] ------- The Corporate Village, Da Vincilaan 7-D1 Voice +32-2-7008453 Fax +32-2-7008622 ---------------- B-1935 Zaventem, Belgium

#13 lore raw

PATCH 2/3 drm modesetting core

In reply to Jesse Barnes

This patch adds the core of the new DRM based modesetting system. It creates several new structures in the DRM, the primary ones being the CRTC, which controls all aspects of your device's CRTC(s), output, which describes and controls the various outputs on your gfx chip (e.g. TMDS, LVDS, VGA, etc.), and mode, which describes graphics modes in enough detail for the output and CRTC callbacks to program them to hardware.

It also contains the user level IOCTL interfaces for doing graphics programming (getting CRTC, output and mode lists, setting up new frame buffer objects, etc.).

It relies on the new TTM patch Dave posted recently.

Jesse

linux-core/Makefile.kernel +0 -0
index 6f5b021..b9684d6 100644
@@ -13,13 +13,15 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o 

drm_dma.o drm_drawable.o \
drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
drm_memory_debug.o ati_pcigart.o drm_sman.o \
drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
- drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o
+ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
+ drm_edid.o drm_modes.o drm_fb.o

 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o 

\
- i915_buffer.o
+ i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \
+ intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o
nouveau_mem.o \
nouveau_object.o nouveau_irq.o \
nv04_timer.o \

linux-core/drmP.h +7 -4
index a3f9ca8..377f447 100644
@@ -164,6 +164,8 @@
 
 #include "drm_compat.h"
 
+#include "drm_crtc.h"
+
 /***********************************************************************/
 /** \name Macros to make printk easier */
 /*@{*/
@@ -429,6 +431,8 @@ typedef struct drm_file {
 
 	drm_open_hash_t refd_object_hash[_DRM_NO_REF_TYPES];
 	void *driver_priv;
+
+	struct list_head fbs;
 } drm_file_t;
 
 /** Wait queue */
@@ -831,6 +835,9 @@ typedef struct drm_device {
 	unsigned int drw_info_length;
 	drm_drawable_info_t **drw_info;
 	/*@} */
+
+	/* DRM mode setting */
+	struct drm_mode_config mode_config;
 } drm_device_t;
 
 #if __OS_HAS_AGP
@@ -1128,10 +1135,6 @@ extern drm_head_t **drm_heads;
 extern struct drm_sysfs_class *drm_class;
 extern struct proc_dir_entry *drm_proc_root;
 
-extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
-extern int drm_wait_on(drm_device_t *dev, wait_queue_head_t *queue,
-		       int timeout, int (*fn)(drm_device_t *dev, void *priv),
-		       void *priv);
 				/* Proc support (drm_proc.h) */
 extern int drm_proc_init(drm_device_t * dev,
 			 int minor,
linux-core/drm_bo.c +0 -0
index 1c7013b..27016d8 100644
@@ -494,6 +494,7 @@ void drm_bo_usage_deref_locked(drm_buffer_object_t * 

bo)
drm_bo_destroy_locked(bo);
}
}
+EXPORT_SYMBOL(drm_bo_usage_deref_locked);

static void drm_bo_base_deref_locked(drm_file_t * priv,
drm_user_object_t * uo)
{
@@ -1624,6 +1625,7 @@ int drm_buffer_object_create(drm_device_t *dev,
drm_bo_usage_deref_unlocked(bo);
return ret;
}
+EXPORT_SYMBOL(drm_buffer_object_create);

static int drm_bo_add_user_object(drm_file_t * priv,
drm_buffer_object_t * bo,
int shareable)
@@ -1732,7 +1734,6 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
drm_buffer_type, &uo);
if (rep.ret)
break;
-
rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break;
case drm_bo_unreference:
@@ -1983,6 +1984,7 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type)

return ret;
}
+EXPORT_SYMBOL(drm_bo_clean_mm);

/**
*Evict all buffers of a particular mem_type, but leave memory manager
@@ -2115,6 +2117,7 @@ int drm_bo_driver_finish(drm_device_t * dev)
mutex_unlock(&dev->bm.init_mutex);
return ret;
}
+EXPORT_SYMBOL(drm_bo_driver_finish);

int drm_bo_driver_init(drm_device_t * dev)
{
@@ -2306,9 +2309,6 @@ void drm_bo_unmap_virtual(drm_buffer_object_t * bo)
loff_t offset = ((loff_t) bo->map_list.hash.key) << PAGE_SHIFT; loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT;

- if (!dev->dev_mapping)
- return;
-
unmap_mapping_range(dev->dev_mapping, offset, holelen, 1);
}

linux-core/drm_bo_move.c +0 -0
index 4f75206..eaeef1b 100644
@@ -128,6 +128,7 @@ int drm_mem_reg_ioremap(drm_device_t * dev, 

drm_bo_mem_reg_t * mem,
*virtual = addr;
return 0;
}
+EXPORT_SYMBOL(drm_mem_reg_ioremap);

/**
* \c Unmap mapping obtained using drm_bo_ioremap
@@ -150,6 +151,7 @@ void drm_mem_reg_iounmap(drm_device_t * dev, drm_bo_mem_reg_t * mem,
iounmap(virtual);
}
}
+EXPORT_SYMBOL(drm_mem_reg_iounmap);

static int drm_copy_io_page(void *dst, void *src, unsigned long page) {

linux-core/drm_bufs.c +0 -0
index 8793ba0..1ba53c8 100644
@@ -57,7 +57,7 @@ static drm_map_list_t 

*drm_find_matching_map(drm_device_t *dev,
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); if (entry->map && map->type == entry->map->type &&
((entry->map->offset == map->offset) ||
- (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
+ ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
return entry;
}
}
@@ -417,6 +417,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
break;
case _DRM_SHM:
vfree(map->handle);
+ dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
break;
case _DRM_AGP:
case _DRM_SCATTER_GATHER:

linux-core/drm_compat.h +7 -0
index bc5fadc..bada1fd 100644
@@ -60,6 +60,13 @@
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
 #undef DRM_IRQ_ARGS
 #define DRM_IRQ_ARGS		int irq, void *arg, struct pt_regs *regs
+
+typedef _Bool bool;
+enum {
+        false   = 0,
+        true    = 1
+};
+
 #endif
 
 #ifndef list_for_each_safe
linux-core/drm_crtc.c new file +7 -0
new file mode 100644
index 0000000..16cf62a
@@ -0,0 +1,1652 @@
+/*
+ * Copyright (c) 2006-2007 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <[email protected]>
+ *
+ * DRM core CRTC related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software 

and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Keith Packard
+ * Eric Anholt <[email protected]>
+ * Dave Airlie <[email protected]>
+ * Jesse Barnes <[email protected]>
+ */
+#include <linux/list.h>
+#include "drm.h"
+#include "drmP.h"
+#include "drm_crtc.h"
+
+/**
+ * drm_idr_get - allocate a new identifier
+ * @dev: DRM device
+ * @ptr: object pointer, used to generate unique ID
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take DRM mode_config
+ * lock around IDR allocation.
+ *
+ * Create a unique identifier based on @ptr in @dev's identifier space. Used
+ * for tracking modes, CRTCs and outputs.
+ *
+ * RETURNS:
+ * New unique (relative to other objects in @dev) integer identifier for the
+ * object.
+ */
+int drm_idr_get(struct drm_device *dev, void *ptr)
+{
+ int new_id = 0;
+ int ret;
+again:
+ if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
+ DRM_ERROR("Ran out memory getting a mode number\n");
+ return 0;
+ }
+
+ spin_lock(&dev->mode_config.config_lock);
+
+ ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id);
+ if (ret == -EAGAIN) {
+ spin_unlock(&dev->mode_config.config_lock);
+ goto again;
+ }
+
+ spin_unlock(&dev->mode_config.config_lock);
+ return new_id;
+}
+
+/**
+ * drm_idr_put - free an identifer
+ * @dev: DRM device
+ * @id: ID to free
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Free @id from @dev's unique identifier pool.
+ */
+void drm_idr_put(struct drm_device *dev, int id)
+{
+ idr_remove(&dev->mode_config.crtc_idr, id);
+}
+
+/**
+ * drm_framebuffer_create - create a new framebuffer object
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take DRM mode_config
+ * lock around mode_config manipulation.
+ *
+ * Creates a new framebuffer objects and adds it to @dev's DRM mode_config.
+ *
+ * RETURNS:
+ * Pointer to new framebuffer or NULL on error.
+ */
+struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) +{
+ struct drm_framebuffer *fb;
+
+ spin_lock(&dev->mode_config.config_lock);
+ /* Limit to single framebuffer for now */
+ if (dev->mode_config.num_fb > 1) {
+ spin_unlock(&dev->mode_config.config_lock);
+ DRM_ERROR("Attempt to add multiple framebuffers failed\n");
+ return NULL;
+ }
+ spin_unlock(&dev->mode_config.config_lock);
+
+ fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL);
+ if (!fb) {
+
+ return NULL;
+ }
+
+ fb->id = drm_idr_get(dev, fb);
+ fb->dev = dev;
+ spin_lock(&dev->mode_config.config_lock);
+ dev->mode_config.num_fb++;
+ list_add(&fb->head, &dev->mode_config.fb_list);
+ spin_unlock(&dev->mode_config.config_lock);
+
+ return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_create);
+
+/**
+ * drm_framebuffer_destroy - remove a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take DRM mode_config
+ * lock around mode_config manipulation.
+ *
+ * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes
+ * it, setting it to NULL.
+ */
+void drm_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ drm_device_t *dev = fb->dev;
+ struct drm_crtc *crtc;
+
+ /* remove from any CRTC */
+ spin_lock(&dev->mode_config.config_lock);
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc->fb == fb)
+ crtc->fb = NULL;
+ }
+
+ drm_idr_put(dev, fb->id);
+ list_del(&fb->head);
+ dev->mode_config.num_fb--;
+ spin_unlock(&dev->mode_config.config_lock);
+
+ kfree(fb);
+}
+
+/**
+ * drm_crtc_create - create a new CRTC object
+ * @dev: DRM device
+ * @funcs: callbacks for the new CRTC
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take DRM mode_config
+ * lock around mode_config manipulation.
+ *
+ * Creates a new CRTC object and adds it to @dev's mode_config structure.
+ *
+ * RETURNS:
+ * Pointer to new CRTC object or NULL on error.
+ */
+struct drm_crtc *drm_crtc_create(drm_device_t *dev,
+ const struct drm_crtc_funcs *funcs)
+{
+ struct drm_crtc *crtc;
+
+ crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL);
+ if (!crtc)
+ return NULL;
+
+ crtc->dev = dev;
+ crtc->funcs = funcs;
+
+ crtc->id = drm_idr_get(dev, crtc);
+
+ spin_lock(&dev->mode_config.config_lock);
+ list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
+ dev->mode_config.num_crtc++;
+ spin_unlock(&dev->mode_config.config_lock);
+
+ return crtc;
+}
+EXPORT_SYMBOL(drm_crtc_create);
+
+/**
+ * drm_crtc_destroy - remove a CRTC object
+ * @crtc: CRTC to remove
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take DRM mode_config
+ * lock around mode_config traversal.
+ *
+ * Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from
+ * its associated DRM device's mode_config. Frees it afterwards.
+ */
+void drm_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_device_t *dev = crtc->dev;
+
+ if (crtc->funcs->cleanup)
+ (*crtc->funcs->cleanup)(crtc);
+
+ spin_lock(&dev->mode_config.config_lock);
+ drm_idr_put(dev, crtc->id);
+ list_del(&crtc->head);
+ dev->mode_config.num_crtc--;
+ spin_unlock(&dev->mode_config.config_lock);
+ kfree(crtc);
+}
+EXPORT_SYMBOL(drm_crtc_destroy);
+
+/**
+ * drm_crtc_in_use - check if a given CRTC is in a mode_config
+ * @crtc: CRTC to check
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Walk @crtc's DRM device's mode_config and see if it's in use.
+ *
+ * RETURNS:
+ * True if @crtc is part of the mode_config, false otherwise.
+ */
+bool drm_crtc_in_use(struct drm_crtc *crtc)
+{
+ struct drm_output *output;
+ drm_device_t *dev = crtc->dev;
+ /* FIXME: Locking around list access? */
+ list_for_each_entry(output, &dev->mode_config.output_list, head)
+ if (output->crtc == crtc)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(drm_crtc_in_use);
+
+/*
+ * Detailed mode info for a standard 640x480@60Hz monitor
+ */
+static struct drm_display_mode std_mode[] = {
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+ 752, 800, 0, 480, 490, 492, 525, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */
+};
+
+/**
+ * drm_crtc_probe_output_modes - get complete set of display modes
+ * @dev: DRM device
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Based on @dev's mode_config layout, scan all the outputs and try to detect
+ * modes on them. Modes will first be added to the output's probed_modes
+ * list, then culled (based on validity and the @maxX, @maxY parameters) and
+ * put into the normal modes list.
+ *
+ * Intended to be used either at bootup time or when major configuration
+ * changes have occurred.
+ *
+ * FIXME: take into account monitor limits
+ */
+void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
+{
+ struct drm_output *output;
+ struct drm_display_mode *mode, *t;
+ int ret;
+ //if (maxX == 0 || maxY == 0)
+ // TODO
+
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+ /* set all modes to the unverified state */
+ list_for_each_entry_safe(mode, t, &output->modes, head)
+ mode->status = MODE_UNVERIFIED;
+
+ output->status = (*output->funcs->detect)(output);
+
+ if (output->status == output_status_disconnected) {
+ DRM_DEBUG("%s is disconnected\n", output->name);
+ /* TODO set EDID to NULL */
+ continue;
+ }
+
+ ret = (*output->funcs->get_modes)(output);
+
+ if (ret) {
+ drm_mode_output_list_update(output);
+ }
+
+ if (maxX && maxY)
+ drm_mode_validate_size(dev, &output->modes, maxX,
+ maxY, 0);
+ list_for_each_entry_safe(mode, t, &output->modes, head) {
+ if (mode->status == MODE_OK)
+ mode->status = (*output->funcs->mode_valid)(output,mode);
+ }
+
+
+ drm_mode_prune_invalid(dev, &output->modes, TRUE);
+
+ if (list_empty(&output->modes)) {
+ struct drm_display_mode *stdmode;
+
+ DRM_DEBUG("No valid modes on %s\n", output->name);
+
+ /* Should we do this here ???
+ * When no valid EDID modes are available we end up
+ * here and bailed in the past, now we add a standard
+ * 640x480@60Hz mode and carry on.
+ */
+ stdmode = drm_mode_duplicate(dev, &std_mode[0]);
+ drm_mode_probed_add(output, stdmode);
+ drm_mode_list_concat(&output->probed_modes,
+ &output->modes);
+
+ DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
+ output->name);
+ }
+
+ drm_mode_sort(&output->modes);
+
+ DRM_DEBUG("Probed modes for %s\n", output->name);
+ list_for_each_entry_safe(mode, t, &output->modes, head) {
+ mode->vrefresh = drm_mode_vrefresh(mode);
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_debug_printmodeline(dev, mode);
+ }
+ }
+}
+
+/**
+ * drm_crtc_set_mode - set a mode
+ * @crtc: CRTC to program
+ * @mode: mode to use
+ * @x: width of mode
+ * @y: height of mode
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance
+ * to fixup or reject the mode prior to trying to set it.
+ *
+ * RETURNS:
+ * True if the mode was set successfully, or false otherwise.
+ */
+bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ int x, int y)
+{
+ drm_device_t *dev = crtc->dev;
+ struct drm_display_mode *adjusted_mode, saved_mode;
+ int saved_x, saved_y;
+ bool didLock = false;
+ bool ret = false;
+ struct drm_output *output;
+
+ adjusted_mode = drm_mode_duplicate(dev, mode);
+
+ crtc->enabled = drm_crtc_in_use(crtc);
+
+ if (!crtc->enabled) {
+ return true;
+ }
+
+ didLock = crtc->funcs->lock(crtc);
+
+ saved_mode = crtc->mode;
+ saved_x = crtc->x;
+ saved_y = crtc->y;
+
+ /* Update crtc values up front so the driver can rely on them for mode
+ * setting.
+ */
+ crtc->mode = *mode;
+ crtc->x = x;
+ crtc->y = y;
+
+ /* XXX short-circuit changes to base location only */
+
+ /* Pass our mode to the outputs and the CRTC to give them a chance to
+ * adjust it according to limitations or output properties, and also
+ * a chance to reject the mode entirely.
+ */
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+ if (output->crtc != crtc)
+ continue;
+
+ if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
+ goto done;
+ }
+ }
+
+ if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) {
+ goto done;
+ }
+
+ /* Prepare the outputs and CRTCs before setting the mode. */
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+ if (output->crtc != crtc)
+ continue;
+
+ /* Disable the output as the first thing we do. */
+ output->funcs->prepare(output);
+ }
+
+ crtc->funcs->prepare(crtc);
+
+ /* Set up the DPLL and any output state that needs to adjust or depend
+ * on the DPLL.
+ */
+ crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y);
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ if (output->crtc == crtc)
+ output->funcs->mode_set(output, mode, adjusted_mode);
+ }
+
+ /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
+ crtc->funcs->commit(crtc);
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ if (output->crtc == crtc) {
+ output->funcs->commit(output);
+#if 0 // TODO def RANDR_12_INTERFACE
+ if (output->randr_output)
+ RRPostPendingProperties (output->randr_output);
+#endif
+ }
+ }
+
+ /* XXX free adjustedmode */
+ drm_mode_destroy(dev, adjusted_mode);
+ ret = TRUE;
+ /* TODO */
+// if (scrn->pScreen)
+// drm_crtc_set_screen_sub_pixel_order(dev);
+
+done:
+ if (!ret) {
+ crtc->x = saved_x;
+ crtc->y = saved_y;
+ crtc->mode = saved_mode;
+ }
+
+ if (didLock)
+ crtc->funcs->unlock (crtc);
+
+ return ret;
+}
+
+/**
+ * drm_set_desired_modes - set a good mode on every CRTC & output
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Each CRTC may have a desired mode associated with it. This routine simply
+ * walks @dev's mode_config and sets the desired mode on every CRTC. Intended
+ * for use at startup time.
+ *
+ * RETURNS:
+ * True if modes were set, false otherwise.
+ */
+bool drm_set_desired_modes(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+ struct drm_output *output, *list_output;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ output = NULL;
+
+ list_for_each_entry(list_output, &dev->mode_config.output_list,
+ head) {
+ if (list_output->crtc == crtc) {
+ output = list_output;
+ break;
+ }
+ }
+ /* Skip disabled crtcs */
+ if (!output) {
+ DRM_DEBUG("skipping disabled crtc\n");
+ continue;
+ }
+
+ if (!drm_crtc_set_mode(crtc, crtc->desired_mode,
+ crtc->desired_x, crtc->desired_y))
+ return false;
+ }
+
+ drm_disable_unused_functions(dev);
+ return true;
+}
+EXPORT_SYMBOL(drm_set_desired_modes);
+
+/**
+ * drm_disable_unused_functions - disable unused objects
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * If an output or CRTC isn't part of @dev's mode_config, it can be disabled
+ * by calling its dpms function, which should power it off.
+ */
+void drm_disable_unused_functions(struct drm_device *dev) +{
+ struct drm_output *output;
+ struct drm_crtc *crtc;
+
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ if (!output->crtc)
+ (*output->funcs->dpms)(output, DPMSModeOff);
+ }
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (!crtc->enabled)
+ crtc->funcs->dpms(crtc, DPMSModeOff);
+ }
+}
+
+/**
+ * drm_mode_probed_add - add a mode to the specified output's probed mode list
+ * @output: output the new mode
+ * @mode: mode data
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take @output's
+ * mode_lock around mode list manipulation.
+ *
+ * Add @mode to @output's mode list for later use.
+ */
+void drm_mode_probed_add(struct drm_output *output,
+ struct drm_display_mode *mode)
+{
+ spin_lock(&output->modes_lock);
+ list_add(&mode->head, &output->probed_modes);
+ spin_unlock(&output->modes_lock);
+}
+EXPORT_SYMBOL(drm_mode_probed_add);
+
+/**
+ * drm_mode_remove - remove and free a mode
+ * @output: output list to modify
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take @output's
+ * mode_lock around mode list manipulation.
+ *
+ * Remove @mode from @output's mode list, then free it.
+ */
+void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode)
+{
+ spin_lock(&output->modes_lock);
+ list_del(&mode->head);
+ spin_unlock(&output->modes_lock);
+ kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_remove);
+
+/**
+ * drm_output_create - create a new output
+ * @dev: DRM device
+ * @funcs: callbacks for this output
+ * @name: user visible name of the output
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take @dev's
+ * mode_config lock around mode list manipulation.
+ *
+ * Creates a new drm_output structure and adds it to @dev's mode_config
+ * structure.
+ *
+ * RETURNS:
+ * Pointer to the new output or NULL on error.
+ */
+struct drm_output *drm_output_create(drm_device_t *dev,
+ const struct drm_output_funcs *funcs,
+ const char *name)
+{
+ struct drm_output *output = NULL;
+
+ output = kzalloc(sizeof(struct drm_output), GFP_KERNEL);
+ if (!output)
+ return NULL;
+
+ output->dev = dev;
+ output->funcs = funcs;
+ output->id = drm_idr_get(dev, output);
+ if (name)
+ strncpy(output->name, name, DRM_OUTPUT_LEN);
+ output->name[DRM_OUTPUT_LEN - 1] = 0;
+ output->subpixel_order = SubPixelUnknown;
+ INIT_LIST_HEAD(&output->probed_modes);
+ INIT_LIST_HEAD(&output->modes);
+ spin_lock_init(&output->modes_lock);
+ /* randr_output? */
+ /* output_set_monitor(output)? */
+ /* check for output_ignored(output)? */
+
+ spin_lock(&dev->mode_config.config_lock);
+ list_add_tail(&output->head, &dev->mode_config.output_list);
+ dev->mode_config.num_output++;
+
+ spin_unlock(&dev->mode_config.config_lock);
+
+ return output;
+
+}
+EXPORT_SYMBOL(drm_output_create);
+
+/**
+ * drm_output_destroy - remove an output
+ * @output: output to remove
+ *
+ * LOCKING:
+ * Process context (either init or calling process). Must take @dev's
+ * mode_config lock around mode list manipulation. Caller must hold
+ * modes lock? (FIXME)
+ *
+ * Call @output's cleanup function, then remove the output from the DRM
+ * mode_config after freeing @output's modes.
+ */
+void drm_output_destroy(struct drm_output *output)
+{
+ struct drm_device *dev = output->dev;
+ struct drm_display_mode *mode, *t;
+
+ if (*output->funcs->cleanup)
+ (*output->funcs->cleanup)(output);
+
+ list_for_each_entry_safe(mode, t, &output->probed_modes, head)
+ drm_mode_remove(output, mode);
+
+ list_for_each_entry_safe(mode, t, &output->modes, head)
+ drm_mode_remove(output, mode);
+
+ spin_lock(&dev->mode_config.config_lock);
+ drm_idr_put(dev, output->id);
+ list_del(&output->head);
+ spin_unlock(&dev->mode_config.config_lock);
+ kfree(output);
+}
+EXPORT_SYMBOL(drm_output_destroy);
+
+/**
+ * drm_output_rename - rename an output
+ * @output: output to rename
+ * @name: new user visible name
+ *
+ * LOCKING:
+ * None.
+ *
+ * Simply stuff a new name into @output's name field, based on @name.
+ *
+ * RETURNS:
+ * True if the name was changed, false otherwise.
+ */
+bool drm_output_rename(struct drm_output *output, const char *name) +{
+ if (!name)
+ return false;
+
+ strncpy(output->name, name, DRM_OUTPUT_LEN);
+ output->name[DRM_OUTPUT_LEN - 1] = 0;
+
+ DRM_DEBUG("Changed name to %s\n", output->name);
+// drm_output_set_monitor(output);
+// if (drm_output_ignored(output))
+// return FALSE;
+
+ return TRUE;
+}
+EXPORT_SYMBOL(drm_output_rename);
+
+/**
+ * drm_mode_create - create a new display mode
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None.
+ *
+ * Create a new drm_display_mode, give it an ID, and return it.
+ *
+ * RETURNS:
+ * Pointer to new mode on success, NULL on error.
+ */
+struct drm_display_mode *drm_mode_create(struct drm_device *dev) +{
+ struct drm_display_mode *nmode;
+
+ nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+ if (!nmode)
+ return NULL;
+
+ nmode->mode_id = drm_idr_get(dev, nmode);
+ return nmode;
+}
+
+/**
+ * drm_mode_destroy - remove a mode
+ * @dev: DRM device
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * None.
+ *
+ * Free @mode's unique identifier, then free it.
+ */
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+ drm_idr_put(dev, mode->mode_id);
+
+ kfree(mode);
+}
+
+/**
+ * drm_mode_config_init - initialize DRM mode_configuration structure
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None, should happen single threaded at init time.
+ *
+ * Initialize @dev's mode_config structure, used for tracking the graphics
+ * configuration of @dev.
+ */
+void drm_mode_config_init(drm_device_t *dev)
+{
+ spin_lock_init(&dev->mode_config.config_lock);
+ INIT_LIST_HEAD(&dev->mode_config.fb_list);
+ INIT_LIST_HEAD(&dev->mode_config.crtc_list);
+ INIT_LIST_HEAD(&dev->mode_config.output_list);
+ idr_init(&dev->mode_config.crtc_idr);
+}
+EXPORT_SYMBOL(drm_mode_config_init);
+
+/**
+ * drm_get_buffer_object - find the buffer object for a given handle
+ * @dev: DRM device
+ * @bo: pointer to caller's buffer_object pointer
+ * @handle: handle to lookup
+ *
+ * LOCKING:
+ * Must take @dev's struct_mutex to protect buffer object lookup.
+ *
+ * Given @handle, lookup the buffer object in @dev and put it in the caller's
+ * @bo pointer.
+ *
+ * RETURNS:
+ * Zero on success, -EINVAL if the handle couldn't be found.
+ */
+static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **bo, unsigned long handle)
+{
+ drm_user_object_t *uo;
+ drm_hash_item_t *hash;
+ int ret;
+
+ *bo = NULL;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_ht_find_item(&dev->object_hash, handle, &hash);
+ if (ret) {
+ DRM_ERROR("Couldn't find handle.\n");
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ uo = drm_hash_entry(hash, drm_user_object_t, hash);
+ if (uo->type != drm_buffer_type) {
+ ret = -EINVAL;
+ goto out_err;
+ }
+
+ *bo = drm_user_object_entry(uo, drm_buffer_object_t, base);
+ ret = 0;
+out_err:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+/**
+ * drm_setup_output - setup an output structure
+ * @output: output to setup
+ * @crtc: CRTC this output belongs to
+ * @mode: desired mode for this output
+ *
+ * LOCKING:
+ * None.
+ *
+ * Setup @output with the parameters given, with its initial coordinates set
+ * at the origin.
+ */
+static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
+{
+ output->crtc = crtc;
+ output->crtc->desired_mode = mode;
+ output->initial_x = 0;
+ output->initial_y = 0;
+}
+
+/**
+ * drm_initial_config - setup a sane initial output configuration
+ * @dev: DRM device
+ * @can_grow: this configuration is growable
+ *
+ * LOCKING:
+ * Must take various locks. (FIXME)
+ *
+ * Scan the CRTCs and outputs and try to put together an initial setup.
+ * At the moment, this is a cloned configuration across all heads with
+ * a new framebuffer object as the backing store.
+ *
+ * FIXME: return value and better initial config.
+ *
+ * RETURNS:
+ * Zero if everything went ok, nonzero otherwise.
+ */
+bool drm_initial_config(drm_device_t *dev, bool can_grow) +{
+ /* do a hardcoded initial configuration here */
+ struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL,
+ *lvds_crtc = NULL;
+ struct drm_output *output;
+ struct drm_framebuffer *fb;
+ drm_buffer_object_t *fbo;
+ unsigned long size, bytes_per_pixel;
+
+ fb = drm_framebuffer_create(dev);
+ if (!fb) {
+ DRM_ERROR("failed to allocate fb.\n");
+ return true;
+ }
+
+ /* bind both CRTCs to this fb */
+ /* only initialise one crtc to enabled state */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ crtc->fb = fb;
+ if (!vga_crtc) {
+ vga_crtc = crtc;
+ crtc->enabled = 1;
+ crtc->desired_x = 0;
+ crtc->desired_y = 0;
+ } else {
+ if (!lvds_crtc) {
+ lvds_crtc = crtc;
+ crtc->enabled = 1;
+ crtc->desired_x = 0;
+ crtc->desired_y = 0;
+ }
+ if (!tmds_crtc) {
+ tmds_crtc = crtc;
+ crtc->enabled = 1;
+ crtc->desired_x = 0;
+ crtc->desired_y = 0;
+ }
+ }
+ }
+
+ drm_crtc_probe_output_modes(dev, 2048, 2048);
+
+ /* hard bind the CRTCS */
+
+ /* bind analog output to one crtc */
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ struct drm_display_mode *des_mode = NULL;
+
+ if (list_empty(&output->modes))
+ continue;
+
+ /* Get the first preferred moded */
+ list_for_each_entry(des_mode, &output->modes, head) {
+ if (des_mode->flags & DRM_MODE_TYPE_PREFERRED)
+ break;
+ }
+
+ if (!des_mode)
+ continue;
+
+ if (!strncmp(output->name, "VGA", 3)) {
+ DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name);
+ drm_setup_output(output, vga_crtc, des_mode);
+ } else if (!strncmp(output->name, "TMDS", 4)) {
+ DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name);
+ drm_setup_output(output, tmds_crtc, des_mode);
+ } else if (!strncmp(output->name, "LVDS", 3)) {
+ DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name);
+ drm_setup_output(output, lvds_crtc, des_mode);
+ } else
+ output->crtc = NULL;
+
+ /* FB config is max of above desired resolutions */
+ /* FIXME: per-output FBs/CRTCs */
+ if (des_mode->hdisplay > fb->width) {
+ fb->width = des_mode->hdisplay;
+ fb->pitch = fb->width;
+ }
+ if (des_mode->vdisplay > fb->height)
+ fb->height = des_mode->vdisplay;
+ }
+
+ /* FIXME: multiple depths */
+ bytes_per_pixel = 4;
+ fb->bits_per_pixel = bytes_per_pixel * 8;
+ fb->depth = bytes_per_pixel * 8;
+ size = fb->width * fb->height * bytes_per_pixel;
+ drm_buffer_object_create(dev, size, drm_bo_type_kernel,
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE,
+ 0, 0, 0,
+ &fbo);
+ DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
+ fb->height, fbo->offset, fbo);
+ fb->offset = fbo->offset;
+ fb->bo = fbo;
+ drmfb_probe(dev, fb);
+
+ return false;
+}
+EXPORT_SYMBOL(drm_initial_config);
+
+/**
+ * drm_mode_config_cleanup - free up DRM mode_config info
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Free up all the outputs and CRTCs associated with this DRM device, then
+ * free up the framebuffers and associated buffer objects.
+ *
+ * FIXME: cleanup any dangling user buffer objects too
+ */
+void drm_mode_config_cleanup(drm_device_t *dev)
+{
+ struct drm_output *output, *ot;
+ struct drm_crtc *crtc, *ct;
+ struct drm_framebuffer *fb, *fbt;
+ list_for_each_entry_safe(output, ot, &dev->mode_config.output_list,
head) {
+ drm_output_destroy(output);
+ }
+
+ list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head)
{
+ drm_crtc_destroy(crtc);
+ }
+
+ list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+ drmfb_remove(dev, fb);
+ /* If this FB was the kernel one, free it */
+ if (fb->bo->type == drm_bo_type_kernel) {
+ mutex_lock(&dev->struct_mutex);
+ drm_bo_usage_deref_locked(fb->bo);
+ mutex_unlock(&dev->struct_mutex);
+ }
+ drm_framebuffer_destroy(fb);
+ }
+}
+EXPORT_SYMBOL(drm_mode_config_cleanup);
+
+/**
+ * drm_crtc_set_config - set a new config from userspace
+ * @crtc: CRTC to setup
+ * @crtc_info: user provided configuration
+ * @new_mode: new mode to set
+ * @output_set: set of outputs for the new config
+ * @fb: new framebuffer
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Setup a new configuration, provided by the user in @crtc_info, and enable
+ * it.
+ *
+ * RETURNS:
+ * Zero. (FIXME)
+ */
+int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb)
+{
+ drm_device_t *dev = crtc->dev;
+ struct drm_crtc **save_crtcs, *new_crtc;
+ bool save_enabled = crtc->enabled;
+ bool changed;
+ struct drm_output *output;
+ int count = 0, ro;
+
+ save_crtcs = kzalloc(dev->mode_config.num_crtc * sizeof(struct
drm_crtc *), GFP_KERNEL);
+ if (!save_crtcs)
+ return -ENOMEM;
+
+ if (crtc->fb != fb)
+ changed = true;
+
+ if (crtc_info->x != crtc->x || crtc_info->y != crtc->y)
+ changed = true;
+
+ if (new_mode && (crtc->mode.mode_id != new_mode->mode_id))
+ changed = true;
+
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ save_crtcs[count++] = output->crtc;
+
+ if (output->crtc == crtc)
+ new_crtc = NULL;
+ else
+ new_crtc = output->crtc;
+
+ for (ro = 0; ro < crtc_info->count_outputs; ro++) {
+ if (output_set[ro] == output)
+ new_crtc = crtc;
+ }
+ if (new_crtc != output->crtc) {
+ changed = true;
+ output->crtc = new_crtc;
+ }
+ }
+
+ if (changed) {
+ crtc->fb = fb;
+ crtc->enabled = (new_mode != NULL);
+ if (new_mode != NULL) {
+ DRM_DEBUG("attempting to set mode from userspace\n");
+ drm_mode_debug_printmodeline(dev, new_mode);
+ if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x,
+ crtc_info->y)) {
+ crtc->enabled = save_enabled;
+ count = 0;
+ list_for_each_entry(output, &dev->mode_config.output_list, head)
+ output->crtc = save_crtcs[count++];
+ kfree(save_crtcs);
+ return -EINVAL;
+ }
+ crtc->desired_x = crtc_info->x;
+ crtc->desired_y = crtc_info->y;
+ crtc->desired_mode = new_mode;
+ }
+ drm_disable_unused_functions(dev);
+ }
+ kfree(save_crtcs);
+ return 0;
+}
+
+/**
+ * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
+ * @out: drm_mode_modeinfo struct to return to the user
+ * @in: drm_display_mode to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
+ * the user.
+ */
+void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in)
+{
+
+ out->id = in->mode_id;
+ out->clock = in->clock;
+ out->hdisplay = in->hdisplay;
+ out->hsync_start = in->hsync_start;
+ out->hsync_end = in->hsync_end;
+ out->htotal = in->htotal;
+ out->hskew = in->hskew;
+ out->vdisplay = in->vdisplay;
+ out->vsync_start = in->vsync_start;
+ out->vsync_end = in->vsync_end;
+ out->vtotal = in->vtotal;
+ out->vscan = in->vscan;
+ out->vrefresh = in->vrefresh;
+ out->flags = in->flags;
+ strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+ out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+}
+
+
+/**
+ * drm_mode_getresources - get graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a set of configuration description structures and return
+ * them to the user, including CRTC, output and framebuffer configuration.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getresources(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_card_res __user *argp = (void __user *)arg;
+ struct drm_mode_card_res card_res;
+ struct list_head *lh;
+ struct drm_framebuffer *fb;
+ struct drm_output *output;
+ struct drm_crtc *crtc;
+ struct drm_mode_modeinfo u_mode;
+ struct drm_display_mode *mode;
+ int retcode = 0;
+ int mode_count= 0;
+ int output_count = 0;
+ int crtc_count = 0;
+ int fb_count = 0;
+ int copied = 0;
+
+ memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+
+ list_for_each(lh, &dev->mode_config.fb_list)
+ fb_count++;
+
+ list_for_each(lh, &dev->mode_config.crtc_list)
+ crtc_count++;
+
+ list_for_each_entry(output, &dev->mode_config.output_list,
+ head) {
+ output_count++;
+ list_for_each(lh, &output->modes)
+ mode_count++;
+ }
+
+ if (copy_from_user(&card_res, argp, sizeof(card_res)))
+ return -EFAULT;
+
+ if (card_res.count_modes == 0) {
+ DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width,
dev->mode_config.max_height);
+ drm_crtc_probe_output_modes(dev, dev->mode_config.max_width,
dev->mode_config.max_height);
+ mode_count = 0;
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ list_for_each(lh, &output->modes)
+ mode_count++;
+ }
+ }
+
+ /* handle this in 4 parts */
+ /* FBs */
+ if (card_res.count_fbs >= fb_count) {
+ copied = 0;
+ list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
+ if (put_user(fb->id, &card_res.fb_id[copied++])) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ card_res.count_fbs = fb_count;
+
+ /* CRTCs */
+ if (card_res.count_crtcs >= crtc_count) {
+ copied = 0;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){
+ DRM_DEBUG("CRTC ID is %d\n", crtc->id);
+ if (put_user(crtc->id, &card_res.crtc_id[copied++])) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ card_res.count_crtcs = crtc_count;
+
+
+ /* Outputs */
+ if (card_res.count_outputs >= output_count) {
+ copied = 0;
+ list_for_each_entry(output, &dev->mode_config.output_list,
+ head) {
+ DRM_DEBUG("OUTPUT ID is %d\n", output->id);
+ if (put_user(output->id, &card_res.output_id[copied++])) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ card_res.count_outputs = output_count;
+
+ /* Modes */
+ if (card_res.count_modes >= mode_count) {
+ copied = 0;
+ list_for_each_entry(output, &dev->mode_config.output_list,
+ head) {
+ list_for_each_entry(mode, &output->modes, head) {
+ drm_crtc_convert_to_umode(&u_mode, mode);
+ if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct
drm_mode_modeinfo))) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ }
+ card_res.count_modes = mode_count;
+
+done:
+ DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs,
+ card_res.count_outputs,
+ card_res.count_modes);
+
+ if (copy_to_user(argp, &card_res, sizeof(card_res)))
+ return -EFAULT;
+
+ return retcode;
+}
+
+/**
+ * drm_mode_getcrtc - get CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a CRTC configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getcrtc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_crtc __user *argp = (void __user *)arg;
+ struct drm_mode_crtc crtc_resp;
+ struct drm_crtc *crtc;
+ struct drm_output *output;
+ int ocount;
+ int retcode = 0;
+
+ if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp)))
+ return -EFAULT;
+
+ crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id);
+ if (!crtc || (crtc->id != crtc_resp.crtc_id))
+ return -EINVAL;
+ crtc_resp.x = crtc->x;
+ crtc_resp.y = crtc->y;
+ crtc_resp.fb_id = 1;
+
+ crtc_resp.outputs = 0;
+ if (crtc->enabled) {
+
+ crtc_resp.mode = crtc->mode.mode_id;
+ ocount = 0;
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ if (output->crtc == crtc)
+ crtc_resp.outputs |= 1 << (ocount++);
+ }
+ } else {
+ crtc_resp.mode = 0;
+ }
+
+ if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp)))
+ return -EFAULT;
+
+ return retcode;
+}
+
+/**
+ * drm_mode_getoutput - get output configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a output configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getoutput(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_get_output __user *argp = (void __user *)arg;
+ struct drm_mode_get_output out_resp;
+ struct drm_output *output;
+ struct drm_display_mode *mode;
+ int mode_count = 0;
+ int retcode = 0;
+ int copied = 0;
+
+ if (copy_from_user(&out_resp, argp, sizeof(out_resp)))
+ return -EFAULT;
+
+ DRM_DEBUG("output id %d:\n", out_resp.output);
+ output= idr_find(&dev->mode_config.crtc_idr, out_resp.output);
+ if (!output || (output->id != out_resp.output))
+ return -EINVAL;
+
+ list_for_each_entry(mode, &output->modes, head)
+ mode_count++;
+
+ strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN);
+ out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0;
+
+ out_resp.mm_width = output->mm_width;
+ out_resp.mm_height = output->mm_height;
+ out_resp.subpixel = output->subpixel_order;
+ out_resp.connection = output->status;
+ if (output->crtc)
+ out_resp.crtc = output->crtc->id;
+ else
+ out_resp.crtc = 0;
+
+ if ((out_resp.count_modes >= mode_count) && mode_count) {
+ copied = 0;
+ list_for_each_entry(mode, &output->modes, head) {
+ if (put_user(mode->mode_id, &out_resp.modes[copied++])) {
+ retcode = -EFAULT;
+ goto done;
+ }
+ }
+ }
+ out_resp.count_modes = mode_count;
+
+done:
+ if (copy_to_user(argp, &out_resp, sizeof(out_resp)))
+ return -EFAULT;
+
+ return retcode;
+}
+
+/**
+ * drm_mode_setcrtc - set CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Build a new CRTC configuration based on user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_setcrtc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_crtc __user *argp = (void __user *)arg;
+ struct drm_mode_crtc crtc_req;
+ struct drm_crtc *crtc;
+ struct drm_output **output_set = NULL, *output;
+ struct drm_display_mode *mode;
+ struct drm_framebuffer *fb = NULL;
+ int retcode = 0;
+ int i;
+
+ if (copy_from_user(&crtc_req, argp, sizeof(crtc_req)))
+ return -EFAULT;
+
+ crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id);
+ if (!crtc || (crtc->id != crtc_req.crtc_id)) {
+ DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id);
+ return -EINVAL;
+ }
+
+ if (crtc_req.mode) {
+
+ /* if we have a mode we need a framebuffer */
+ if (crtc_req.fb_id) {
+ fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id);
+ if (!fb || (fb->id != crtc_req.fb_id)) {
+ DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id);
+ return -EINVAL;
+ }
+ }
+ mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode);
+ if (!mode || (mode->mode_id != crtc_req.mode)) {
+ struct drm_output *output;
+
+ list_for_each_entry(output, &dev->mode_config.output_list, head) {
+ list_for_each_entry(mode, &output->modes, head) {
+ drm_mode_debug_printmodeline(dev, mode);
+ }
+ }
+
+ DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode);
+ return -EINVAL;
+ }
+ } else
+ mode = NULL;
+
+ if (crtc_req.count_outputs == 0 && mode) {
+ DRM_DEBUG("Count outputs is 0 but mode set\n");
+ return -EINVAL;
+ }
+
+ if (crtc_req.count_outputs > 0 && !mode && !fb) {
+ DRM_DEBUG("Count outputs is %d but no mode or fb set\n",
crtc_req.count_outputs);
+ return -EINVAL;
+ }
+
+ if (crtc_req.count_outputs > 0) {
+ u32 out_id;
+ output_set = kmalloc(crtc_req.count_outputs * sizeof(struct
drm_output *), GFP_KERNEL);
+ if (!output_set)
+ return -ENOMEM;
+
+ for (i = 0; i < crtc_req.count_outputs; i++) {
+ if (get_user(out_id, &crtc_req.set_outputs[i]))
+ return -EFAULT;
+
+ output = idr_find(&dev->mode_config.crtc_idr, out_id);
+ if (!output || (out_id != output->id)) {
+ DRM_DEBUG("Output id %d unknown\n", out_id);
+ return -EINVAL;
+ }
+
+ output_set[i] = output;
+ }
+ }
+
+ retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb);
+ return retcode;
+}
+
+/**
+ * drm_mode_addfb - add an FB to the graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Add a new FB to the specified CRTC, given a user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_addfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_mode_fb_cmd __user *argp = (void __user *)arg;
+ struct drm_mode_fb_cmd r;
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_framebuffer *fb;
+ struct drm_buffer_object *bo;
+ int ret;
+
+ if (copy_from_user(&r, argp, sizeof(r)))
+ return -EFAULT;
+
+ if ((config->min_width > r.width) || (r.width > config->max_width)) {
+ DRM_ERROR("mode new framebuffer width not within limits\n");
+ return -EINVAL;
+ }
+ if ((config->min_height > r.height) || (r.height >
config->max_height)) {
+ DRM_ERROR("mode new framebuffer height not within limits\n");
+ return -EINVAL;
+ }
+
+ /* TODO check limits are okay */
+ ret = drm_get_buffer_object(dev, &bo, r.handle);
+ if (ret || !bo)
+ return -EINVAL;
+
+ /* TODO check buffer is sufficently large */
+ /* TODO setup destructor callback */
+
+ fb = drm_framebuffer_create(dev);
+ if(!fb)
+ return -EINVAL;;
+
+ fb->width = r.width;
+ fb->height = r.height;
+ fb->pitch = r.pitch;
+ fb->bits_per_pixel = r.bpp;
+ fb->depth = r.depth;
+ fb->offset = bo->offset;
+ fb->bo = bo;
+
+ r.buffer_id = fb->id;
+
+ list_add(&fb->filp_head, &priv->fbs);
+ /* bind the fb to the crtc for now */
+ {
+ struct drm_crtc *crtc;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ crtc->fb = fb;
+ }
+ }
+ if (copy_to_user(argp, &r, sizeof(r)))
+ return -EFAULT;
+
+ drmfb_probe(dev, fb);
+ return 0;
+}
+
+/**
+ * drm_mode_rmfb - remove an FB from the configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Remove the FB specified by the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_rmfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_framebuffer *fb = 0;
+ uint32_t id = arg;
+
+ fb = idr_find(&dev->mode_config.crtc_idr, id);
+ /* TODO check that we realy get a framebuffer back. */
+ if (!fb || (id != fb->id)) {
+ DRM_ERROR("mode invalid framebuffer id\n");
+ return -EINVAL;
+ }
+
+ drmfb_remove(dev, fb);
+ /* TODO check if we own the buffer */
+ /* TODO release all crtc connected to the framebuffer */
+ /* bind the fb to the crtc for now */
+ /* TODO unhock the destructor from the buffer object */
+
+ drm_framebuffer_destroy(fb);
+
+ return 0;
+}
+
+/**
+ * drm_mode_getfb - get FB info
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_mode_fb_cmd __user *argp = (void __user *)arg;
+ struct drm_mode_fb_cmd r;
+ struct drm_framebuffer *fb;
+
+ if (copy_from_user(&r, argp, sizeof(r)))
+ return -EFAULT;
+
+ fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id);
+ if (!fb || (r.buffer_id != fb->id)) {
+ DRM_ERROR("invalid framebuffer id\n");
+ return -EINVAL;
+ }
+
+ r.height = fb->height;
+ r.width = fb->width;
+ r.depth = fb->depth;
+ r.bpp = fb->bits_per_pixel;
+ r.handle = fb->bo->base.hash.key;
+ r.pitch = fb->pitch;
+
+ if (copy_to_user(argp, &r, sizeof(r)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
+ * drm_fb_release - remove and free the FBs on this file
+ * @filp: file * from the ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Destroy all the FBs associated with @filp.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+void drm_fb_release(struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ struct drm_framebuffer *fb, *tfb;
+
+ list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+ list_del(&fb->filp_head);
+ drmfb_remove(dev, fb);
+ drm_framebuffer_destroy(fb);
+
+ }
+}

linux-core/drm_crtc.h new file +19 -0
new file mode 100644
index 0000000..a15ce0c
@@ -0,0 +1,535 @@
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2007 Intel Corporation
+ *   Jesse Barnes <[email protected]>
+ */
+#ifndef __DRM_CRTC_H__
+#define __DRM_CRTC_H__
+
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+
+#include <linux/fb.h>
+
+struct drm_device;
+
+/*
+ * Note on terminology:  here, for brevity and convenience, we refer to 

output
+ * control chips as 'CRTCs'. They can control any type of output, VGA, LVDS,
+ * DVI, etc. And 'screen' refers to the whole of the visible display, which
+ * may span multiple monitors (and therefore multiple CRTC and output
+ * structures).
+ */
+
+enum drm_mode_status {

+    MODE_OK	= 0,	/* Mode OK */
+    MODE_HSYNC,		/* hsync out of range */
+    MODE_VSYNC,		/* vsync out of range */
+    MODE_H_ILLEGAL,	/* mode has illegal horizontal timings */
+    MODE_V_ILLEGAL,	/* mode has illegal horizontal timings */
+    MODE_BAD_WIDTH,	/* requires an unsupported linepitch */
+    MODE_NOMODE,	/* no mode with a maching name */
+    MODE_NO_INTERLACE,	/* interlaced mode not supported */
+    MODE_NO_DBLESCAN,	/* doublescan mode not supported */
+    MODE_NO_VSCAN,	/* multiscan mode not supported */
+    MODE_MEM,		/* insufficient video memory */
+    MODE_VIRTUAL_X,	/* mode width too large for specified virtual size 
*/
+    MODE_VIRTUAL_Y,	/* mode height too large for specified virtual size 
*/
+    MODE_MEM_VIRT,	/* insufficient video memory given virtual size */
+    MODE_NOCLOCK,	/* no fixed clock available */
+    MODE_CLOCK_HIGH,	/* clock required is too high */
+    MODE_CLOCK_LOW,	/* clock required is too low */
+    MODE_CLOCK_RANGE,	/* clock/mode isn't in a ClockRange */
+    MODE_BAD_HVALUE,	/* horizontal timing was out of range */
+    MODE_BAD_VVALUE,	/* vertical timing was out of range */
+    MODE_BAD_VSCAN,	/* VScan value out of range */
+    MODE_HSYNC_NARROW,	/* horizontal sync too narrow */
+    MODE_HSYNC_WIDE,	/* horizontal sync too wide */
+    MODE_HBLANK_NARROW,	/* horizontal blanking too narrow */
+    MODE_HBLANK_WIDE,	/* horizontal blanking too wide */
+    MODE_VSYNC_NARROW,	/* vertical sync too narrow */
+    MODE_VSYNC_WIDE,	/* vertical sync too wide */
+    MODE_VBLANK_NARROW,	/* vertical blanking too narrow */
+    MODE_VBLANK_WIDE,	/* vertical blanking too wide */
+    MODE_PANEL,         /* exceeds panel dimensions */
+    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
+    MODE_ONE_WIDTH,     /* only one width is supported */
+    MODE_ONE_HEIGHT,    /* only one height is supported */
+    MODE_ONE_SIZE,      /* only one resolution is supported */
+    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_UNVERIFIED = -3, /* mode needs to reverified */
+    MODE_BAD = -2,	/* unspecified reason */
+    MODE_ERROR	= -1	/* error condition */

+};
+
+#define DRM_MODE_TYPE_BUILTIN (1<<0)
+#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_PREFERRED (1<<3)
+#define DRM_MODE_TYPE_DEFAULT (1<<4)
+#define DRM_MODE_TYPE_USERDEF (1<<5)
+#define DRM_MODE_TYPE_DRIVER (1<<6)
+
+#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
+ DRM_MODE_TYPE_CRTC_C)
+
+#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs,
f) \
+ .name = nm, .status = 0, .type = (t), .clock = (c), \
+ .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
+ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
+ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
+ .vscan = (vs), .flags = (f), .vrefresh = 0
+
+struct drm_display_mode {
+ /* Header */
+ struct list_head head;
+ char name[DRM_DISPLAY_MODE_LEN];
+ int mode_id;
+ enum drm_mode_status status;
+ int type;
+
+ /* Proposed mode values */
+ int clock;
+ int hdisplay;
+ int hsync_start;
+ int hsync_end;
+ int htotal;
+ int hskew;
+ int vdisplay;
+ int vsync_start;
+ int vsync_end;
+ int vtotal;
+ int vscan;
+ unsigned int flags;
+
+ /* Actual mode we give to hw */
+ int clock_index;
+ int synth_clock;
+ int crtc_hdisplay;
+ int crtc_hblank_start;
+ int crtc_hblank_end;
+ int crtc_hsync_start;
+ int crtc_hsync_end;
+ int crtc_htotal;
+ int crtc_hskew;
+ int crtc_vdisplay;
+ int crtc_vblank_start;
+ int crtc_vblank_end;
+ int crtc_vsync_start;
+ int crtc_vsync_end;
+ int crtc_vtotal;
+ int crtc_hadjusted;
+ int crtc_vadjusted;
+
+ /* Driver private mode info */
+ int private_size;
+ int *private;
+ int private_flags;
+
+ int vrefresh;
+ float hsync;
+};
+
+/* Video mode flags */
+#define V_PHSYNC (1<<0)
+#define V_NHSYNC (1<<1)
+#define V_PVSYNC (1<<2)
+#define V_NVSYNC (1<<3)
+#define V_INTERLACE (1<<4)
+#define V_DBLSCAN (1<<5)
+#define V_CSYNC (1<<6)
+#define V_PCSYNC (1<<7)
+#define V_NCSYNC (1<<8)
+#define V_HSKEW (1<<9) /* hskew provided */
+#define V_BCAST (1<<10)
+#define V_PIXMUX (1<<11)
+#define V_DBLCLK (1<<12)
+#define V_CLKDIV2 (1<<13)
+
+#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ +#define DPMSModeOn 0
+#define DPMSModeStandby 1
+#define DPMSModeSuspend 2
+#define DPMSModeOff 3
+
+enum drm_output_status {
+ output_status_connected,
+ output_status_disconnected,
+ output_status_unknown,
+};
+
+enum subpixel_order {
+ SubPixelUnknown = 0,
+ SubPixelHorizontalRGB,
+ SubPixelHorizontalBGR,
+ SubPixelVerticalRGB,
+ SubPixelVerticalBGR,
+ SubPixelNone,
+};
+
+/*
+ * Describes a given display (e.g. CRT or flat panel) and its limitations.
+ */
+struct drm_display_info {
+ char name[DRM_DISPLAY_INFO_LEN];
+ /* Input info */
+ bool serration_vsync;
+ bool sync_on_green;
+ bool composite_sync;
+ bool separate_syncs;
+ bool blank_to_black;
+ unsigned char video_level;
+ bool digital;
+ /* Physical size */
+ unsigned int width_mm;
+ unsigned int height_mm;
+
+ /* Display parameters */
+ unsigned char gamma; /* FIXME: storage format */
+ bool gtf_supported;
+ bool standard_color;
+ enum {
+ monochrome,
+ rgb,
+ other,
+ unknown,
+ } display_type;
+ bool active_off_supported;
+ bool suspend_supported;
+ bool standby_supported;
+
+ /* Color info FIXME: storage format */
+ unsigned short redx, redy;
+ unsigned short greenx, greeny;
+ unsigned short bluex, bluey;
+ unsigned short whitex, whitey;
+
+ /* Clock limits FIXME: storage format */
+ unsigned int min_vfreq, max_vfreq;
+ unsigned int min_hfreq, max_hfreq;
+ unsigned int pixel_clock;
+
+ /* White point indices FIXME: storage format */
+ unsigned int wpx1, wpy1;
+ unsigned int wpgamma1;
+ unsigned int wpx2, wpy2;
+ unsigned int wpgamma2;
+
+ /* Preferred mode (if any) */
+ struct drm_display_mode *preferred_mode;
+ char *raw_edid; /* if any */
+};
+
+struct drm_framebuffer {
+ struct drm_device *dev;
+ struct list_head head;
+ int id; /* idr assigned */
+ unsigned int pitch;
+ unsigned long offset;
+ unsigned int width;
+ unsigned int height;
+ /* depth can be 15 or 16 */
+ unsigned int depth;
+ int bits_per_pixel;
+ int flags;
+ struct drm_buffer_object *bo;
+ void *fbdev;
+ u32 pseudo_palette[17];
+ void *virtual_base;
+ struct list_head filp_head;
+};
+struct drm_crtc;
+struct drm_output;
+
+/**
+ * drm_crtc_funcs - control CRTCs for a given device
+ * @dpms: control display power levels
+ * @save: save CRTC state
+ * @resore: restore CRTC state
+ * @lock: lock the CRTC
+ * @unlock: unlock the CRTC
+ * @shadow_allocate: allocate shadow pixmap
+ * @shadow_create: create shadow pixmap for rotation support
+ * @shadow_destroy: free shadow pixmap
+ * @mode_fixup: fixup proposed mode
+ * @mode_set: set the desired mode on the CRTC
+ * @gamma_set: specify color ramp for CRTC
+ * @cleanup: cleanup driver private state prior to close
+ *
+ * The drm_crtc_funcs structure is the central CRTC management structure
+ * in the DRM. Each CRTC controls one or more outputs (note that the name
+ * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
+ * outputs, not just CRTs).
+ *
+ * Each driver is responsible for filling out this structure at startup time,
+ * in addition to providing other modesetting features, like i2c and DDC
+ * bus accessors.
+ */
+struct drm_crtc_funcs {
+ /*
+ * Control power levels on the CRTC. If the mode passed in is
+ * unsupported, the provider must use the next lowest power level.
+ */
+ void (*dpms)(struct drm_crtc *crtc, int mode);
+
+ /* JJJ: Are these needed? */
+ /* Save CRTC state */
+ void (*save)(struct drm_crtc *crtc); /* suspend? */
+ /* Restore CRTC state */
+ void (*restore)(struct drm_crtc *crtc); /* resume? */
+ bool (*lock)(struct drm_crtc *crtc);
+ void (*unlock)(struct drm_crtc *crtc);
+
+ void (*prepare)(struct drm_crtc *crtc);
+ void (*commit)(struct drm_crtc *crtc);
+
+ /* Provider can fixup or change mode timings before modeset occurs */
+ bool (*mode_fixup)(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+ /* Actually set the mode */
+ void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode, int x, int y);
+ /* Set gamma on the CRTC */
+ void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
+ int size);
+ /* Driver cleanup routine */
+ void (*cleanup)(struct drm_crtc *crtc);
+};
+
+/**
+ * drm_crtc - central CRTC control structure
+ * @enabled: is this CRTC enabled?
+ * @x: x position on screen
+ * @y: y position on screen
+ * @desired_mode: new desired mode
+ * @desired_x: desired x for desired_mode
+ * @desired_y: desired y for desired_mode
+ * @funcs: CRTC control functions
+ * @driver_private: arbitrary driver data
+ *
+ * Each CRTC may have one or more outputs associated with it. This structure
+ * allows the CRTC to be controlled.
+ */
+struct drm_crtc {
+ struct drm_device *dev;
+ struct list_head head;
+
+ int id; /* idr assigned */
+
+ /* framebuffer the CRTC is currently bound to */
+ struct drm_framebuffer *fb;
+
+ bool enabled;
+
+ /* JJJ: are these needed? */
+ bool cursor_in_range;
+ bool cursor_shown;
+
+ struct drm_display_mode mode;
+
+ int x, y;
+ struct drm_display_mode *desired_mode;
+ int desired_x, desired_y;
+ const struct drm_crtc_funcs *funcs;
+ void *driver_private;
+
+ /* RRCrtcPtr randr_crtc? */
+};
+
+extern struct drm_crtc *drm_crtc_create(struct drm_device *dev,
+ const struct drm_crtc_funcs *funcs);
+
+/**
+ * drm_output_funcs - control outputs on a given device
+ * @init: setup this output
+ * @dpms: set power state (see drm_crtc_funcs above)
+ * @save: save output state
+ * @restore: restore output state
+ * @mode_valid: is this mode valid on the given output?
+ * @mode_fixup: try to fixup proposed mode for this output
+ * @mode_set: set this mode
+ * @detect: is this output active?
+ * @get_modes: get mode list for this output
+ * @set_property: property for this output may need update
+ * @cleanup: output is going away, cleanup
+ *
+ * Each CRTC may have one or more outputs attached to it. The functions
+ * below allow the core DRM code to control outputs, enumerate available modes,
+ * etc.
+ */
+struct drm_output_funcs {
+ void (*init)(struct drm_output *output);
+ void (*dpms)(struct drm_output *output, int mode);
+ void (*save)(struct drm_output *output);
+ void (*restore)(struct drm_output *output);
+ int (*mode_valid)(struct drm_output *output,
+ struct drm_display_mode *mode);
+ bool (*mode_fixup)(struct drm_output *output,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+ void (*prepare)(struct drm_output *output);
+ void (*commit)(struct drm_output *output);
+ void (*mode_set)(struct drm_output *output,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+ enum drm_output_status (*detect)(struct drm_output *output);
+ int (*get_modes)(struct drm_output *output);
+ /* JJJ: type checking for properties via property value type */
+ bool (*set_property)(struct drm_output *output, int prop, void *val);
+ void (*cleanup)(struct drm_output *output);
+};
+
+#define DRM_OUTPUT_LEN 32
+/**
+ * drm_output - central DRM output control structure
+ * @crtc: CRTC this output is currently connected to, NULL if none
+ * @possible_crtcs: bitmap of CRTCS this output could be attached to
+ * @possible_clones: bitmap of possible outputs this output could clone
+ * @interlace_allowed: can this output handle interlaced modes?
+ * @doublescan_allowed: can this output handle doublescan?
+ * @available_modes: modes available on this output (from get_modes() + user)
+ * @initial_x: initial x position for this output
+ * @initial_y: initial y position for this output
+ * @status: output connected?
+ * @subpixel_order: for this output
+ * @mm_width: displayable width of output in mm
+ * @mm_height: displayable height of output in mm
+ * @name: name of output (should be one of a few standard names)
+ * @funcs: output control functions
+ * @driver_private: private driver data
+ *
+ * Each output may be connected to one or more CRTCs, or may be clonable by
+ * another output if they can share a CRTC. Each output also has a specific
+ * position in the broader display (referred to as a 'screen' though it could
+ * span multiple monitors).
+ */
+struct drm_output {
+ struct drm_device *dev;
+ struct list_head head;
+ struct drm_crtc *crtc;
+ int id; /* idr assigned */
+ unsigned long possible_crtcs;
+ unsigned long possible_clones;
+ bool interlace_allowed;
+ bool doublescan_allowed;
+ spinlock_t modes_lock; /* protects modes and probed_modes lists */
+ struct list_head modes; /* list of modes on this output */
+ /*
+ OptionInfoPtr options;
+ XF86ConfMonitorPtr conf_monitor;
+ */
+ int initial_x, initial_y;
+ enum drm_output_status status;
+
+ /* these are modes added by probing with DDC or the BIOS */
+ struct list_head probed_modes;
+
+ /* xf86MonPtr MonInfo; */
+ enum subpixel_order subpixel_order;
+ int mm_width, mm_height;
+ struct drm_display_info *monitor_info; /* if any */
+ char name[DRM_OUTPUT_LEN];
+ const struct drm_output_funcs *funcs;
+ void *driver_private;
+ /* RROutputPtr randr_output? */
+};
+
+/**
+ * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
+ * @resize: adjust CRTCs as necessary for the proposed layout
+ *
+ * Currently only a resize hook is available. DRM will call back into the
+ * driver with a new screen width and height. If the driver can't support
+ * the proposed size, it can return false. Otherwise it should adjust
+ * the CRTC<->output mappings as needed and update its view of the screen.
+ */
+struct drm_mode_config_funcs {
+ bool (*resize)(struct drm_device *dev, int width, int height);
+};
+
+/**
+ * drm_mode_config - Mode configuration control structure
+ *
+ */
+struct drm_mode_config {
+ spinlock_t config_lock; /* protects configuration and IDR */
+ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output,
modes - just makes life easier */
+ /* this is limited to one for now */
+ int num_fb;
+ struct list_head fb_list;
+ int num_output;
+ struct list_head output_list;
+
+ /* int compat_output? */
+ int num_crtc;
+ struct list_head crtc_list;
+
+ int min_width, min_height;
+ int max_width, max_height;
+ /* DamagePtr rotationDamage? */
+ /* DGA stuff? */
+ struct drm_mode_config_funcs *funcs;
+ unsigned long fb_base;
+};
+
+struct drm_output *drm_output_create(struct drm_device *dev,
+ const struct drm_output_funcs *funcs,
+ const char *name);
+extern void drm_output_destroy(struct drm_output *output); +extern bool drm_output_rename(struct drm_output *output, const char *name);
+
+extern int drm_add_edid_modes(struct drm_output *output,
+ struct i2c_adapter *adapter);
+extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode);
+extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode);
+extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+ struct drm_display_mode *mode);
+extern void drm_mode_debug_printmodeline(struct drm_device *dev,
+ struct drm_display_mode *mode);
+extern void drm_mode_config_init(struct drm_device *dev); +extern void drm_mode_config_cleanup(struct drm_device *dev); +extern void drm_mode_set_name(struct drm_display_mode *mode); +extern void drm_disable_unused_functions(struct drm_device *dev); +
+extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
+extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
+extern void drm_mode_list_concat(struct list_head *head,
+ struct list_head *new);
+extern void drm_mode_validate_size(struct drm_device *dev,
+ struct list_head *mode_list,
+ int maxX, int maxY, int maxPitch);
+extern void drm_mode_prune_invalid(struct drm_device *dev,
+ struct list_head *mode_list, bool verbose);
+extern void drm_mode_sort(struct list_head *mode_list); +extern int drm_mode_vrefresh(struct drm_display_mode *mode); +extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
+ int adjust_flags);
+extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
+extern bool drm_initial_config(struct drm_device *dev, bool cangrow); +extern void drm_framebuffer_set_object(struct drm_device *dev,
+ unsigned long handle);
+extern bool drm_set_desired_modes(struct drm_device *dev); +extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb);
+extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+
+/* IOCTLs */
+extern int drm_mode_getresources(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern int drm_mode_getcrtc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mode_getoutput(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mode_setcrtc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mode_addfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mode_rmfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int drm_mode_getfb(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+#endif /* __DRM_CRTC_H__ */
+

linux-core/drm_drv.c +0 -0
index e5788d7..5aa7137 100644
@@ -123,6 +123,13 @@ static drm_ioctl_desc_t drm_ioctls[] = {
 					     DRM_AUTH },
 
 	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, 

DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources,
DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc,
DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput,
DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc,
DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|
DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|
DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETFB)] = {drm_mode_getfb, DRM_MASTER|
DRM_ROOT_ONLY},
};

#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -140,7 +147,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
int drm_lastclose(drm_device_t * dev)
{
drm_magic_entry_t *pt, *next;
- drm_map_list_t *r_list;
+ drm_map_list_t *r_list, *r_list_tmp;
drm_vma_entry_t *vma, *vma_next;
int i;

@@ -150,8 +157,6 @@ int drm_lastclose(drm_device_t * dev)
* We can't do much about this function failing. */

- drm_bo_driver_finish(dev);
-
if (dev->driver->lastclose)
dev->driver->lastclose(dev);
DRM_DEBUG("driver lastclose completed\n");
@@ -233,10 +238,9 @@ int drm_lastclose(drm_device_t * dev)
}

if (dev->maplist) {
- while (!list_empty(&dev->maplist->head)) {
- struct list_head *list = dev->maplist->head.next;
- r_list = list_entry(list, drm_map_list_t, head);
- drm_rmmap_locked(dev, r_list->map);
+ list_for_each_entry_safe(r_list, r_list_tmp,
&dev->maplist->head, head) {
+ if (!(r_list->map->flags & _DRM_DRIVER))
+ drm_rmmap_locked(dev, r_list->map);
}
}

@@ -260,8 +264,7 @@ int drm_lastclose(drm_device_t * dev)
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
drm_dma_takedown(dev);

- if (dev->lock.hw_lock) {
- dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
+ if (dev->lock.filp) {
dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue);
}
@@ -372,17 +375,6 @@ static void drm_cleanup(drm_device_t * dev)
drm_lastclose(dev); drm_fence_manager_takedown(dev);

- if (dev->maplist) {
- drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
- dev->maplist = NULL;
- drm_ht_remove(&dev->map_hash);
- drm_mm_takedown(&dev->offset_manager);
- drm_ht_remove(&dev->object_hash);
- }
-
- if (!drm_fb_loaded)
- pci_disable_device(dev->pdev);
-
drm_ctxbitmap_cleanup(dev);

if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && dev->agp
@@ -394,12 +386,26 @@ static void drm_cleanup(drm_device_t * dev)
DRM_DEBUG("mtrr_del=%d\n", retval);
}

+ if (dev->driver->unload)
+ dev->driver->unload(dev);
+
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); dev->agp = NULL;
}
- if (dev->driver->unload)
- dev->driver->unload(dev);
+
+
+ // drm_bo_driver_finish(dev);
+ if (dev->maplist) {
+ drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ dev->maplist = NULL;
+ drm_ht_remove(&dev->map_hash);
+ drm_mm_takedown(&dev->offset_manager);
+ drm_ht_remove(&dev->object_hash);
+ }
+
+ if (!drm_fb_loaded)
+ pci_disable_device(dev->pdev);

drm_put_head(&dev->primary);
if (drm_put_dev(dev))
@@ -622,45 +628,3 @@ err_i1:
return retcode;
}
EXPORT_SYMBOL(drm_ioctl);
-
-int drm_wait_on(drm_device_t *dev, wait_queue_head_t *queue, int timeout,
- int (*fn)(drm_device_t *dev, void *priv), void *priv)
-{
- DECLARE_WAITQUEUE(entry, current);
- unsigned long end = jiffies + (timeout);
- int ret = 0;
- add_wait_queue(queue, &entry);
-
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- if ((*fn)(dev, priv))
- break;
- if (time_after_eq(jiffies, end)) {
- ret = -EBUSY;
- break;
- }
- schedule_timeout((HZ/100 > 1) ? HZ/100 : 1);
- if (signal_pending(current)) {
- ret = -EINTR;
- break;
- }
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(queue, &entry);
- return ret;
-}
-EXPORT_SYMBOL(drm_wait_on);
-
-drm_local_map_t *drm_getsarea(struct drm_device *dev) -{
- drm_map_list_t *entry;
-
- list_for_each_entry(entry, &dev->maplist->head, head) {
- if (entry->map && entry->map->type == _DRM_SHM &&
- (entry->map->flags & _DRM_CONTAINS_LOCK)) {
- return entry->map;
- }
- }
- return NULL;
-}
-EXPORT_SYMBOL(drm_getsarea);

linux-core/drm_edid.c new file +5 -0
new file mode 100644
index 0000000..0d06792
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <[email protected]>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) 

originally from
+ * FB layer.
+ * Copyright (C) 2006 Dennis Munsie <[email protected]>
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/* Valid EDID header has these bytes */
+static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+/**
+ * edid_valid - sanity check EDID data
+ * @edid: EDID data
+ *
+ * Sanity check the EDID block by looking at the header, the version number
+ * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
+ * valid.
+ */
+static bool edid_valid(struct edid *edid)
+{
+ int i;
+ u8 csum = 0;
+ u8 *raw_edid = (u8 *)edid;
+
+ if (memcmp(edid->header, edid_header, sizeof(edid_header)))
+ goto bad;
+ if (edid->version != 1)
+ goto bad;
+ if (edid->revision <= 0 || edid->revision > 3)
+ goto bad;
+
+ for (i = 0; i < EDID_LENGTH; i++)
+ csum += raw_edid[i];
+ if (csum)
+ goto bad;
+
+ return 1;
+
+bad:
+ return 0;
+}
+
+/**
+ * drm_mode_std - convert standard mode info (width, height, refresh) into mode
+ * @t: standard timing params
+ *
+ * Take the standard timing params (in this case width, aspect, and refresh)
+ * and convert them into a real mode using CVT.
+ *
+ * Punts for now, but should eventually use the FB layer's CVT based mode
+ * generation code.
+ */
+struct drm_display_mode *drm_mode_std(struct drm_device *dev,
+ struct std_timing *t)
+{
+// struct fb_videomode mode;
+
+// fb_find_mode_cvt(&mode, 0, 0);
+ /* JJJ: convert to drm_display_mode */
+ struct drm_display_mode *mode;
+ int hsize = t->hsize * 8 + 248, vsize;
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return NULL;
+
+ if (t->aspect_ratio == 0)
+ vsize = (hsize * 10) / 16;
+ else if (t->aspect_ratio == 1)
+ vsize = (hsize * 3) / 4;
+ else if (t->aspect_ratio == 2)
+ vsize = (hsize * 4) / 5;
+ else
+ vsize = (hsize * 9) / 16;
+
+ drm_mode_set_name(mode);
+
+ return mode;
+}
+
+/**
+ * drm_mode_detailed - create a new mode from an EDID detailed timing section
+ * @timing: EDID detailed timing info
+ * @preferred: is this a preferred mode?
+ *
+ * An EDID detailed timing block contains enough info for us to create and
+ * return a new struct drm_display_mode. The @preferred flag will be set
+ * if this is the display's preferred timing, and we'll use it to indicate
+ * to the other layers that this mode is desired.
+ */
+struct drm_display_mode *drm_mode_detailed(drm_device_t *dev,
+ struct detailed_timing *timing)
+{
+ struct drm_display_mode *mode;
+ struct detailed_pixel_timing *pt = &timing->data.pixel_data;
+
+ if (pt->stereo) {
+ printk(KERN_WARNING "stereo mode not supported\n");
+ return NULL;
+ }
+ if (!pt->separate_sync) {
+ printk(KERN_WARNING "integrated sync not supported\n");
+ return NULL;
+ }
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return NULL;
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ mode->clock = timing->pixel_clock * 10;
+
+ mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo;
+ mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) |
+ pt->hsync_offset_lo);
+ mode->hsync_end = mode->hsync_start +
+ ((pt->hsync_pulse_width_hi << 8) |
+ pt->hsync_pulse_width_lo);
+ mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) |
pt->hblank_lo);
+
+ mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
+ mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) |
+ pt->vsync_offset_lo);
+ mode->vsync_end = mode->vsync_start +
+ ((pt->vsync_pulse_width_hi << 8) |
+ pt->vsync_pulse_width_lo);
+ mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) |
pt->vblank_lo);
+
+ drm_mode_set_name(mode);
+
+ if (pt->interlaced)
+ mode->flags |= V_INTERLACE;
+
+ mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC;
+ mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC;
+
+ return mode;
+}
+
+/*
+ * Detailed mode info for the EDID "established modes" data to use.
+ */
+static struct drm_display_mode edid_est_modes[] = {
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+ 968, 1056, 0, 600, 601, 605, 628, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+ 896, 1024, 0, 600, 601, 603, 625, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+ 720, 840, 0, 480, 481, 484, 500, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+ 704, 832, 0, 480, 489, 491, 520, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
+ 768, 864, 0, 480, 483, 486, 525, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+ 752, 800, 0, 480, 490, 492, 525, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */
+ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
+ 846, 900, 0, 400, 421, 423, 449, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */
+ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
+ 846, 900, 0, 400, 412, 414, 449, 0,
+ V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */
+ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+ 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
+ 1136, 1312, 0, 768, 769, 772, 800, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+ 1184, 1328, 0, 768, 771, 777, 806, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+ 1184, 1344, 0, 768, 771, 777, 806, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+ 1208, 1264, 0, 768, 768, 776, 817, 0,
+ V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */
+ { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
+ 928, 1152, 0, 624, 625, 628, 667, 0,
+ V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+ 896, 1056, 0, 600, 601, 604, 625, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+ 976, 1040, 0, 600, 637, 643, 666, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */
+ { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+ 1344, 1600, 0, 864, 865, 868, 900, 0,
+ V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */
+};
+
+#define EDID_EST_TIMINGS 16
+#define EDID_STD_TIMINGS 8
+#define EDID_DETAILED_TIMINGS 4
+
+/**
+ * add_established_modes - get est. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Each EDID block contains a bitmap of the supported "established modes" list
+ * (defined above). Tease them out and add them to the global modes list.
+ */
+static int add_established_modes(struct drm_output *output, struct edid *edid)
+{
+ struct drm_device *dev = output->dev;
+ unsigned long est_bits = edid->established_timings.t1 |
+ (edid->established_timings.t2 << 8) |
+ ((edid->established_timings.mfg_rsvd & 0x80) << 9);
+ int i, modes = 0;
+
+ for (i = 0; i <= EDID_EST_TIMINGS; i++)
+ if (est_bits & (1<<i)) {
+ struct drm_display_mode *newmode;
+ newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
+ drm_mode_probed_add(output, newmode);
+ modes++;
+ }
+
+ return modes;
+}
+
+/**
+ * add_standard_modes - get std. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Standard modes can be calculated using the CVT standard. Grab them from
+ * @edid, calculate them, and add them to the list.
+ */
+static int add_standard_modes(struct drm_output *output, struct edid *edid)
+{
+ struct drm_device *dev = output->dev;
+ int i, modes = 0;
+
+ for (i = 0; i < EDID_STD_TIMINGS; i++) {
+ struct std_timing *t = &edid->standard_timings[i];
+ struct drm_display_mode *newmode;
+
+ /* If std timings bytes are 1, 1 it's empty */
+ if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1)
+ continue;
+
+ newmode = drm_mode_std(dev, &edid->standard_timings[i]);
+ drm_mode_probed_add(output, newmode);
+ modes++;
+ }
+
+ return modes;
+}
+
+/**
+ * add_detailed_modes - get detailed mode info from EDID data
+ * @edid: EDID block to scan
+ *
+ * Some of the detailed timing sections may contain mode information. Grab
+ * it and add it to the list.
+ */
+static int add_detailed_info(struct drm_output *output, struct edid *edid)
+{
+ struct drm_device *dev = output->dev;
+ int i, j, modes = 0;
+
+ for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
+ struct detailed_timing *timing = &edid->detailed_timings[i];
+ struct detailed_non_pixel *data = &timing->data.other_data;
+ struct drm_display_mode *newmode;
+
+ /* EDID up to and including 1.2 may put monitor info here */
+ if (edid->version == 1 && edid->revision < 3)
+ continue;
+
+ /* Detailed mode timing */
+ if (timing->pixel_clock) {
+ newmode = drm_mode_detailed(dev, timing);
+ /* First detailed mode is preferred */
+ if (i == 0 && edid->preferred_timing)
+ newmode->type |= DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(output, newmode);
+
+ modes++;
+ continue;
+ }
+
+ /* Other timing or info */
+ switch (data->type) {
+ case EDID_DETAIL_MONITOR_SERIAL:
+ break;
+ case EDID_DETAIL_MONITOR_STRING:
+ break;
+ case EDID_DETAIL_MONITOR_RANGE:
+ /* Get monitor range data */
+ break;
+ case EDID_DETAIL_MONITOR_NAME:
+ break;
+ case EDID_DETAIL_MONITOR_CPDATA:
+ break;
+ case EDID_DETAIL_STD_MODES:
+ /* Five modes per detailed section */
+ for (j = 0; j < 5; i++) {
+ struct std_timing *std;
+ struct drm_display_mode *newmode;
+
+ std = &data->data.timings[j];
+ newmode = drm_mode_std(dev, std);
+ drm_mode_probed_add(output, newmode);
+ modes++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return modes;
+}
+
+#define DDC_ADDR 0x50
+
+static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+ unsigned char start = 0x0;
+ unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = &start,
+ }, {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = EDID_LENGTH,
+ .buf = buf,
+ }
+ };
+
+ if (!buf) {
+ dev_warn(&adapter->dev, "unable to allocate memory for EDID "
+ "block.\n");
+ return NULL;
+ }
+
+ if (i2c_transfer(adapter, msgs, 2) == 2)
+ return buf;
+
+ dev_info(&adapter->dev, "unable to read EDID block.\n");
+ kfree(buf);
+ return NULL;
+}
+
+static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) +{
+ struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+ unsigned char *edid = NULL;
+ int i, j;
+
+ /*
+ * Startup the bus:
+ * Set clock line high (but give it time to come up)
+ * Then set clock & data low
+ */
+ algo_data->setscl(algo_data->data, 1);
+ udelay(550); /* startup delay */
+ algo_data->setscl(algo_data->data, 0);
+ algo_data->setsda(algo_data->data, 0);
+
+ for (i = 0; i < 3; i++) {
+ /* For some old monitors we need the
+ * following process to initialize/stop DDC
+ */
+ algo_data->setsda(algo_data->data, 0);
+ msleep(13);
+
+ algo_data->setscl(algo_data->data, 1);
+ for (j = 0; j < 5; j++) {
+ msleep(10);
+ if (algo_data->getscl(algo_data->data))
+ break;
+ }
+ if (j == 5)
+ continue;
+
+ algo_data->setsda(algo_data->data, 0);
+ msleep(15);
+ algo_data->setscl(algo_data->data, 0);
+ msleep(15);
+ algo_data->setsda(algo_data->data, 1);
+ msleep(15);
+
+ /* Do the real work */
+ edid = drm_do_probe_ddc_edid(adapter);
+ algo_data->setsda(algo_data->data, 0);
+ algo_data->setscl(algo_data->data, 0);
+ msleep(15);
+
+ algo_data->setscl(algo_data->data, 1);
+ for (j = 0; j < 10; j++) {
+ msleep(10);
+ if (algo_data->getscl(algo_data->data))
+ break;
+ }
+
+ algo_data->setsda(algo_data->data, 1);
+ msleep(15);
+ algo_data->setscl(algo_data->data, 0);
+ if (edid)
+ break;
+ }
+ /* Release the DDC lines when done or the Apple Cinema HD display
+ * will switch off
+ */
+ algo_data->setsda(algo_data->data, 0);
+ algo_data->setscl(algo_data->data, 0);
+ algo_data->setscl(algo_data->data, 1);
+
+ return edid;
+}
+
+/**
+ * drm_add_edid_modes - add modes from EDID data, if available
+ * @output: output we're probing
+ * @adapter: i2c adapter to use for DDC
+ *
+ * Poke the given output's i2c channel to grab EDID data if possible. If we
+ * get any, add the specified modes to the output's mode list.
+ *
+ * Return number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter)
+{
+ struct edid *edid;
+ int num_modes = 0;
+
+ edid = (struct edid *)drm_ddc_read(adapter);
+ if (!edid) {
+ dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n",
+ output->name);
+ goto out_err;
+ }
+
+ if (!edid_valid(edid)) {
+ dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n",
+ output->name);
+ goto out_err;
+ }
+
+ num_modes += add_established_modes(output, edid);
+ num_modes += add_standard_modes(output, edid);
+ num_modes += add_detailed_info(output, edid);
+
+ return num_modes;
+
+out_err:
+ kfree(edid);
+ return 0;
+}
+EXPORT_SYMBOL(drm_add_edid_modes);

linux-core/drm_edid.h new file +69 -0

69 lines not on this page · raw message

order */
+ u8 hfreq_start_khz; /* need to multiply by 2 */
+ u8 c; /* need to divide by 2 */
+ u16 m; /* FIXME: byte order */
+ u8 k;
+ u8 j; /* need to divide by 2 */
+} __attribute__((packed));
+
+struct detailed_data_wpindex {
+ u8 white_y_lo:2;
+ u8 white_x_lo:2;
+ u8 pad:4;
+ u8 white_x_hi;
+ u8 white_y_hi;
+ u8 gamma; /* need to divide by 100 then add 1 */
+} __attribute__((packed));
+
+struct detailed_data_color_point {
+ u8 windex1;
+ u8 wpindex1[3];
+ u8 windex2;
+ u8 wpindex2[3];
+} __attribute__((packed));
+
+struct detailed_non_pixel {
+ u8 pad1;
+ u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
+ fb=color point data, fa=standard timing data,
+ f9=undefined, f8=mfg. reserved */
+ u8 pad2;
+ union {
+ struct detailed_data_string str;
+ struct detailed_data_monitor_range range;
+ struct detailed_data_wpindex color;
+ struct std_timing timings[5];
+ } data;
+} __attribute__((packed));
+
+#define EDID_DETAIL_STD_MODES 0xfa
+#define EDID_DETAIL_MONITOR_CPDATA 0xfb
+#define EDID_DETAIL_MONITOR_NAME 0xfc
+#define EDID_DETAIL_MONITOR_RANGE 0xfd
+#define EDID_DETAIL_MONITOR_STRING 0xfe
+#define EDID_DETAIL_MONITOR_SERIAL 0xff
+
+struct detailed_timing {
+ u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order
*/
+ union {
+ struct detailed_pixel_timing pixel_data;
+ struct detailed_non_pixel other_data;
+ } data;
+} __attribute__((packed));
+
+struct edid {
+ u8 header[8];
+ /* Vendor & product info */
+ u16 mfg_id; /* FIXME: byte order */
+ u16 prod_code; /* FIXME: byte order */
+ u32 serial; /* FIXME: byte order */
+ u8 mfg_week;
+ u8 mfg_year;
+ /* EDID version */
+ u8 version;
+ u8 revision;
+ /* Display info: */
+ /* input definition */
+ u8 serration_vsync:1;
+ u8 sync_on_green:1;
+ u8 composite_sync:1;
+ u8 separate_syncs:1;
+ u8 blank_to_black:1;
+ u8 video_level:2;
+ u8 digital:1; /* bits below must be zero if set */
+ u8 width_cm;
+ u8 height_cm;
+ u8 gamma;
+ /* feature support */
+ u8 default_gtf:1;
+ u8 preferred_timing:1;
+ u8 standard_color:1;
+ u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+ u8 pm_active_off:1;
+ u8 pm_suspend:1;
+ u8 pm_standby:1;
+ /* Color characteristics */
+ u8 red_green_lo;
+ u8 black_white_lo;
+ u8 red_x;
+ u8 red_y;
+ u8 green_x;
+ u8 green_y;
+ u8 blue_x;
+ u8 blue_y;
+ u8 white_x;
+ u8 white_y;
+ /* Est. timings and mfg rsvd timings*/
+ struct est_timings established_timings;
+ /* Standard timings 1-8*/
+ struct std_timing standard_timings[8];
+ /* Detailing timings 1-4 */
+ struct detailed_timing detailed_timings[4];
+ /* Number of 128 byte ext. blocks */
+ u8 extensions;
+ /* Checksum */
+ u8 checksum;
+} __attribute__((packed));
+
+#endif /* __DRM_EDID_H__ */

linux-core/drm_fb.c new file +4 -0
new file mode 100644
index 0000000..ef05341
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2007 David Airlie
+ *
+ * Permission is hereby granted, free of charge, to any person 

obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * David Airlie
+ */
+ /*
+ * Modularization
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+struct drmfb_par {
+ struct drm_device *dev;
+ struct drm_framebuffer *fb;
+};
+
+static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ struct drmfb_par *par = info->par;
+ struct drm_framebuffer *fb = par->fb;
+ if (regno > 17)
+ return 1;
+
+ if (regno < 16) {
+ switch (fb->depth) {
+ case 15:
+ fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 16:
+ fb->pseudo_palette[regno] = (red & 0xf800) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 24:
+ case 32:
+ fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+ (green & 0xff00) |
+ ((blue & 0xff00) >> 8);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* this will let fbcon do the mode init */
+static int drmfb_set_par(struct fb_info *info)
+{
+ struct drmfb_par *par = info->par;
+ struct drm_device *dev = par->dev;
+
+ drm_set_desired_modes(dev);
+ return 0;
+}
+
+static struct fb_ops drmfb_ops = {
+ .owner = THIS_MODULE,
+ // .fb_open = drmfb_open,
+ // .fb_read = drmfb_read,
+ // .fb_write = drmfb_write,
+ // .fb_release = drmfb_release,
+ // .fb_ioctl = drmfb_ioctl,
+ .fb_set_par = drmfb_set_par,
+ .fb_setcolreg = drmfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +{
+ struct fb_info *info;
+ struct drmfb_par *par;
+ struct device *device = &dev->pdev->dev;
+ struct fb_var_screeninfo *var_info;
+ unsigned long base, size;
+ int ret;
+
+ info = framebuffer_alloc(sizeof(struct drmfb_par), device);
+ if (!info){
+ return -EINVAL;
+ }
+
+ fb->fbdev = info;
+
+ par = info->par;
+
+ par->dev = dev;
+ par->fb = fb;
+
+ info->fbops = &drmfb_ops;
+
+ strcpy(info->fix.id, "drmfb");
+ info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
+ info->fix.smem_len = (8*1024*1024);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.type_aux = 0;
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8);
+
+ info->flags = FBINFO_DEFAULT;
+
+ ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
+ if (ret)
+ DRM_ERROR("error mapping fb: %d\n", ret);
+
+ info->screen_base = fb->virtual_base;
+ info->screen_size = size;
+ info->pseudo_palette = fb->pseudo_palette;
+ info->var.xres = fb->width;
+ info->var.xres_virtual = fb->pitch;
+ info->var.yres = fb->height;
+ info->var.yres_virtual = fb->height;
+ info->var.bits_per_pixel = fb->bits_per_pixel;
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ DRM_DEBUG("fb depth is %d\n", fb->depth);
+ switch(fb->depth) {
+ case 8:
+ case 15:
+ case 16:
+ break;
+ default:
+ case 24:
+ case 32:
+ info->var.red.offset = 16;
+ info->var.green.offset = 8;
+ info->var.blue.offset = 0;
+ info->var.red.length = info->var.green.length =
+ info->var.blue.length = 8;
+ if (fb->depth == 32) {
+ info->var.transp.offset = 24;
+ info->var.transp.length = 8;
+ }
+ break;
+ }
+
+ if (register_framebuffer(info) < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+ return 0;
+}
+EXPORT_SYMBOL(drmfb_probe);
+
+int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{
+ struct fb_info *info = fb->fbdev;
+
+ if (info) {
+ drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
+ unregister_framebuffer(info);
+ framebuffer_release(info);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(drmfb_remove);
+MODULE_LICENSE("GPL");

linux-core/drm_fops.c +1 -1
index d400a4d..e474897 100644
@@ -86,7 +86,7 @@ static int drm_setup(drm_device_t * dev)
 	INIT_LIST_HEAD(&dev->ctxlist->head);
 
 	dev->vmalist = NULL;
-	dev->sigdata.lock = NULL;
+	//	dev->sigdata.lock = NULL;
 	init_waitqueue_head(&dev->lock.lock_queue);
 	dev->queue_count = 0;
 	dev->queue_reserved = 0;
@@ -270,6 +270,7 @@ static int drm_open_helper(struct inode *inode, 

struct file *filp,

INIT_LIST_HEAD(&priv->user_objects);
INIT_LIST_HEAD(&priv->refd_objects);
+ INIT_LIST_HEAD(&priv->fbs);

for (i=0; i<_DRM_NO_REF_TYPES; ++i) {
ret = drm_ht_create(&priv->refd_object_hash[i], DRM_FILE_HASH_ORDER);
@@ -501,6 +502,7 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_unlock(&dev->ctxlist_mutex);

mutex_lock(&dev->struct_mutex);
+ drm_fb_release(filp);
drm_object_release(filp);
if (priv->remove_auth_on_close == 1) {
drm_file_t *temp = dev->file_first;

linux-core/drm_modes.c new file +4 -0
new file mode 100644
index 0000000..3293f91
@@ -0,0 +1,558 @@
+/*
+ * Copyright © 1997-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person 

obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+/*
+ * Copyright © 2007 Dave Airlie
+ */
+
+#include <linux/list.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+
+/**
+ * drm_mode_debug_printmodeline - debug print a mode
+ * @dev: DRM device
+ * @mode: mode to print
+ *
+ * LOCKING:
+ * None.
+ *
+ * Describe @mode using DRM_DEBUG.
+ */
+void drm_mode_debug_printmodeline(struct drm_device *dev,
+ struct drm_display_mode *mode)
+{
+ DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d\n",

+		  mode->mode_id, mode->name, mode->vrefresh, mode->clock,
+		  mode->hdisplay, mode->hsync_start,
+		  mode->hsync_end, mode->htotal,
+		  mode->vdisplay, mode->vsync_start,
+		  mode->vsync_end, mode->vtotal);

+}
+EXPORT_SYMBOL(drm_mode_debug_printmodeline);
+
+/**
+ * drm_mode_set_name - set the name on a mode
+ * @mode: name will be set in this mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Set the name of @mode to a standard format.
+ */
+void drm_mode_set_name(struct drm_display_mode *mode)
+{
+ snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay,
+ mode->vdisplay);
+}
+EXPORT_SYMBOL(drm_mode_set_name);
+
+/**
+ * drm_mode_list_concat - move modes from one list to another
+ * @head: source list
+ * @new: dst list
+ *
+ * LOCKING:
+ * Caller must ensure both lists are locked.
+ *
+ * Move all the modes from @head to @new.
+ */
+void drm_mode_list_concat(struct list_head *head, struct list_head *new)
+{
+
+ struct list_head *entry, *tmp;
+
+ list_for_each_safe(entry, tmp, head) {
+ list_move_tail(entry, new);
+ }
+}
+
+/**
+ * drm_mode_width - get the width of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's width (hdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->hdisplay
+ */
+int drm_mode_width(struct drm_display_mode *mode)
+{
+ return mode->hdisplay;
+
+}
+EXPORT_SYMBOL(drm_mode_width);
+
+/**
+ * drm_mode_height - get the height of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's height (vdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->vdisplay
+ */
+int drm_mode_height(struct drm_display_mode *mode)
+{
+ return mode->vdisplay;
+}
+EXPORT_SYMBOL(drm_mode_height);
+
+/**
+ * drm_mode_vrefresh - get the vrefresh of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's vrefresh rate or calculate it if necessary.
+ *
+ * FIXME: why is this needed?
+ *
+ * RETURNS:
+ * Vertical refresh rate of @mode x 1000. For precision reasons.
+ */
+int drm_mode_vrefresh(struct drm_display_mode *mode)
+{
+ int refresh = 0;
+ unsigned int calc_val;
+
+ if (mode->vrefresh > 0)
+ refresh = mode->vrefresh;
+ else if (mode->htotal > 0 && mode->vtotal > 0) {
+ /* work out vrefresh the value will be x1000 */
+ calc_val = (mode->clock * 1000);
+
+ calc_val /= mode->htotal;
+ calc_val *= 1000;
+ calc_val /= mode->vtotal;
+
+ refresh = calc_val;
+ if (mode->flags & V_INTERLACE)
+ refresh *= 2;
+ if (mode->flags & V_DBLSCAN)
+ refresh /= 2;
+ if (mode->vscan > 1)
+ refresh /= mode->vscan;
+ }
+ return refresh;
+}
+EXPORT_SYMBOL(drm_mode_vrefresh);
+
+/**
+ * drm_mode_set_crtcinfo - set CRTC modesetting parameters
+ * @p: mode
+ * @adjust_flags: unused? (FIXME)
+ *
+ * LOCKING:
+ * None.
+ *
+ * Setup the CRTC modesetting parameters for @p, adjusting if necessary.
+ */
+void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
+{
+ if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) ==
DRM_MODE_TYPE_BUILTIN))
+ return;
+
+ p->crtc_hdisplay = p->hdisplay;
+ p->crtc_hsync_start = p->hsync_start;
+ p->crtc_hsync_end = p->hsync_end;
+ p->crtc_htotal = p->htotal;
+ p->crtc_hskew = p->hskew;
+ p->crtc_vdisplay = p->vdisplay;
+ p->crtc_vsync_start = p->vsync_start;
+ p->crtc_vsync_end = p->vsync_end;
+ p->crtc_vtotal = p->vtotal;
+
+ if (p->flags & V_INTERLACE) {
+ if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
+ p->crtc_vdisplay /= 2;
+ p->crtc_vsync_start /= 2;
+ p->crtc_vsync_end /= 2;
+ p->crtc_vtotal /= 2;
+ }
+
+ p->crtc_vtotal |= 1;
+ }
+
+ if (p->flags & V_DBLSCAN) {
+ p->crtc_vdisplay *= 2;
+ p->crtc_vsync_start *= 2;
+ p->crtc_vsync_end *= 2;
+ p->crtc_vtotal *= 2;
+ }
+
+ if (p->vscan > 1) {
+ p->crtc_vdisplay *= p->vscan;
+ p->crtc_vsync_start *= p->vscan;
+ p->crtc_vsync_end *= p->vscan;
+ p->crtc_vtotal *= p->vscan;
+ }
+
+ p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
+ p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
+ p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
+ p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
+
+ p->crtc_hadjusted = false;
+ p->crtc_vadjusted = false;
+}
+EXPORT_SYMBOL(drm_mode_set_crtcinfo);
+
+
+/**
+ * drm_mode_duplicate - allocate and duplicate an existing mode
+ * @m: mode to duplicate
+ *
+ * LOCKING:
+ * None.
+ *
+ * Just allocate a new mode, copy the existing mode into it, and return
+ * a pointer to it. Used to create new instances of established modes.
+ */
+struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+ struct drm_display_mode *mode)
+{
+ struct drm_display_mode *nmode;
+ int new_id;
+
+ nmode = drm_mode_create(dev);
+ if (!nmode)
+ return NULL;
+
+ new_id = nmode->mode_id;
+ *nmode = *mode;
+ nmode->mode_id = new_id;
+ INIT_LIST_HEAD(&nmode->head);
+ return nmode;
+}
+EXPORT_SYMBOL(drm_mode_duplicate);
+
+/**
+ * drm_mode_equal - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Check to see if @mode1 and @mode2 are equivalent.
+ *
+ * RETURNS:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2)
+{
+ if (mode1->clock == mode2->clock &&

+	    mode1->hdisplay == mode2->hdisplay &&
+	    mode1->hsync_start == mode2->hsync_start &&
+	    mode1->hsync_end == mode2->hsync_end &&
+	    mode1->htotal == mode2->htotal &&
+	    mode1->hskew == mode2->hskew &&
+	    mode1->vdisplay == mode2->vdisplay &&
+	    mode1->vsync_start == mode2->vsync_start &&
+	    mode1->vsync_end == mode2->vsync_end &&
+	    mode1->vtotal == mode2->vtotal &&
+	    mode1->vscan == mode2->vscan &&
+	    mode1->flags == mode2->flags)

+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_validate_size - make sure modes adhere to size constraints
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @maxX: maximum width
+ * @maxY: maximum height
+ * @maxPitch: max pitch
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * The DRM device (@dev) has size and pitch limits. Here we validate the
+ * modes we probed for @dev against those limits and set their status as
+ * necessary.
+ */
+void drm_mode_validate_size(struct drm_device *dev,
+ struct list_head *mode_list,
+ int maxX, int maxY, int maxPitch)
+{
+ struct drm_display_mode *mode;
+
+ list_for_each_entry(mode, mode_list, head) {
+ if (maxPitch > 0 && mode->hdisplay > maxPitch)
+ mode->status = MODE_BAD_WIDTH;
+
+ if (maxX > 0 && mode->hdisplay > maxX)
+ mode->status = MODE_VIRTUAL_X;
+
+ if (maxY > 0 && mode->vdisplay > maxY)
+ mode->status = MODE_VIRTUAL_Y;
+ }
+}
+EXPORT_SYMBOL(drm_mode_validate_size);
+
+/**
+ * drm_mode_validate_clocks - validate modes against clock limits
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @min: minimum clock rate array
+ * @max: maximum clock rate array
+ * @n_ranges: number of clock ranges (size of arrays)
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Some code may need to check a mode list against the clock limits of the
+ * device in question. This function walks the mode list, testing to make
+ * sure each mode falls within a given range (defined by @min and @max
+ * arrays) and sets @mode->status as needed.
+ */
+void drm_mode_validate_clocks(struct drm_device *dev,
+ struct list_head *mode_list,
+ int *min, int *max, int n_ranges)
+{
+ struct drm_display_mode *mode;
+ int i;
+
+ list_for_each_entry(mode, mode_list, head) {
+ bool good = false;
+ for (i = 0; i < n_ranges; i++) {
+ if (mode->clock >= min[i] && mode->clock <= max[i]) {
+ good = true;
+ break;
+ }
+ }
+ if (!good)
+ mode->status = MODE_CLOCK_RANGE;
+ }
+}
+EXPORT_SYMBOL(drm_mode_validate_clocks);
+
+/**
+ * drm_mode_prune_invalid - remove invalid modes from mode list
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @verbose: be verbose about it
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Once mode list generation is complete, a caller can use this routine to
+ * remove invalid modes from a mode list. If any of the modes have a
+ * status other than %MODE_OK, they are removed from @mode_list and freed.
+ */
+void drm_mode_prune_invalid(struct drm_device *dev,
+ struct list_head *mode_list, bool verbose)
+{
+ struct drm_display_mode *mode, *t;
+
+ list_for_each_entry_safe(mode, t, mode_list, head) {
+ if (mode->status != MODE_OK) {
+ list_del(&mode->head);
+ if (verbose)
+ DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
+ kfree(mode);
+ }
+ }
+}
+
+/**
+ * drm_mode_compare - compare modes for favorability
+ * @lh_a: list_head for first mode
+ * @lh_b: list_head for second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
+ * which is better.
+ *
+ * RETURNS:
+ * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
+ * positive if @lh_b is better than @lh_a.
+ */
+static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b)
+{
+ struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode,
head);
+ struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode,
head);
+ int diff;
+
+ diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
+ ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
+ if (diff)
+ return diff;
+ diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
+ if (diff)
+ return diff;
+ diff = b->clock - a->clock;
+ return diff;
+}
+
+/* FIXME: what we don't have a list sort function? */
+/* list sort from Mark J Roberts ([email protected]) */
+void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b))
+{
+ struct list_head *p, *q, *e, *list, *tail, *oldhead;
+ int insize, nmerges, psize, qsize, i;
+
+ list = head->next;
+ list_del(head);
+ insize = 1;
+ for (;;) {
+ p = oldhead = list;
+ list = tail = NULL;
+ nmerges = 0;
+
+ while (p) {
+ nmerges++;
+ q = p;
+ psize = 0;
+ for (i = 0; i < insize; i++) {
+ psize++;
+ q = q->next == oldhead ? NULL : q->next;
+ if (!q)
+ break;
+ }
+
+ qsize = insize;
+ while (psize > 0 || (qsize > 0 && q)) {
+ if (!psize) {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ } else if (!qsize || !q) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else if (cmp(p, q) <= 0) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ }
+ if (tail)
+ tail->next = e;
+ else
+ list = e;
+ e->prev = tail;
+ tail = e;
+ }
+ p = q;
+ }
+
+ tail->next = list;
+ list->prev = tail;
+
+ if (nmerges <= 1)
+ break;
+
+ insize *= 2;
+ }
+
+ head->next = list;
+ head->prev = list->prev;
+ list->prev->next = head;
+ list->prev = head;
+}
+
+/**
+ * drm_mode_sort - sort mode list
+ * @mode_list: list to sort
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Sort @mode_list by favorability, putting good modes first.
+ */
+void drm_mode_sort(struct list_head *mode_list)
+{
+ list_sort(mode_list, drm_mode_compare);
+}
+
+
+/**
+ * drm_mode_output_list_update - update the mode list for the output
+ * @output: the output to update
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * This moves the modes from the @output probed_modes list
+ * to the actual mode list. It compares the probed mode against the current
+ * list and only adds different modes. All modes unverified after this point
+ * will be removed by the prune invalid modes.
+ */
+void drm_mode_output_list_update(struct drm_output *output) +{
+ struct drm_display_mode *mode, *t;
+ struct drm_display_mode *pmode, *pt;
+ int found_it;
+ list_for_each_entry_safe(pmode, pt, &output->probed_modes,
+ head) {
+ found_it = 0;
+ /* go through current modes checking for the new probed mode */
+ list_for_each_entry(mode, &output->modes, head) {
+ if (drm_mode_equal(pmode, mode)) {
+ found_it = 1;
+ /* if equal delete the probed mode */
+ mode->status = pmode->status;
+ list_del(&pmode->head);
+ kfree(pmode);
+ break;
+ }
+ }
+
+ if (!found_it) {
+ list_move_tail(&pmode->head, &output->modes);
+ }
+ }
+}

linux-core/drm_objects.h +8 -5
index 03ea927..8a70c73 100644
@@ -29,7 +29,8 @@
  */
 
 #ifndef _DRM_OBJECTS_H
-#define _DRM_OBJECTS_H
+#define _DRM_OJBECTS_H
+#define DRM_HAS_TTM
 
 struct drm_device;
 
@@ -247,9 +248,9 @@ typedef struct drm_ttm_backend_func {
 
 
 typedef struct drm_ttm_backend {
-	uint32_t flags;
-	int mem_type;
-	drm_ttm_backend_func_t *func;
+        uint32_t flags;
+        int mem_type;
+        drm_ttm_backend_func_t *func;
 } drm_ttm_backend_t;
 
 typedef struct drm_ttm {
@@ -427,7 +428,13 @@ typedef struct drm_bo_driver {
 /*
  * buffer objects (drm_bo.c)
  */
-
+extern int drm_bo_init_mm(struct drm_device * dev, unsigned type,
+			  unsigned long p_offset, unsigned long p_size);
+extern int drm_buffer_object_create(struct drm_device *dev, unsigned 

long size,

+				    drm_bo_type_t type, uint32_t mask,
+				    uint32_t hint, uint32_t page_alignment,
+				    unsigned long buffer_start,
+				    drm_buffer_object_t ** buf_obj);

extern int drm_bo_ioctl(DRM_IOCTL_ARGS);
extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS);
extern int drm_bo_driver_finish(struct drm_device *dev);
@@ -471,4 +478,9 @@ extern int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo,
uint32_t fence_flags, drm_bo_mem_reg_t * new_mem);

+extern int drm_mem_reg_ioremap(struct drm_device *dev, drm_bo_mem_reg_t
* mem,
+ void **virtual);
+extern void drm_mem_reg_iounmap(struct drm_device *dev, drm_bo_mem_reg_t * mem,
+ void *virtual);
+
#endif

linux-core/drm_os_linux.h +0 -0
index 2ea105c..816959e 100644
@@ -119,6 +119,24 @@ static __inline__ int mtrr_del(int reg, unsigned 

long base, unsigned long size)

#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv =
_filp->private_data

+/**
+ * Get the pointer to the SAREA.
+ *
+ * Searches the SAREA on the mapping lists and points drm_device::sarea to it.
+ */
+#define DRM_GETSAREA() \
+do { \
+ drm_map_list_t *entry; \
+ list_for_each_entry( entry, &dev->maplist->head, head ) { \
+ if ( entry->map && \
+ entry->map->type == _DRM_SHM && \
+ (entry->map->flags & _DRM_CONTAINS_LOCK) ) { \
+ dev_priv->sarea = entry->map; \
+ break; \
+ } \
+ } \
+} while (0)
+
#define DRM_HZ HZ

#define DRM_WAIT_ON( ret, queue, timeout, condition ) \

linux-core/drm_stub.c +0 -0
index f4da7da..01ffe67 100644
@@ -79,27 +79,28 @@ static int drm_fill_in_dev(drm_device_t * dev, 

struct pci_dev *pdev,
#endif
dev->irq = pdev->irq;

- if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) {
- drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER))
return -ENOMEM;
- }
+
if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START,
DRM_FILE_PAGE_OFFSET_SIZE)) {
- drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
drm_ht_remove(&dev->map_hash);
return -ENOMEM;
}

if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) {
- drm_free(dev->maplist, sizeof(*dev->maplist),
DRM_MEM_MAPS);
drm_ht_remove(&dev->map_hash); drm_mm_takedown(&dev->offset_manager); return -ENOMEM;
}

dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
- if (dev->maplist == NULL)
+ if (dev->maplist == NULL) {
+ drm_ht_remove(&dev->object_hash);
+ drm_ht_remove(&dev->map_hash);
+ drm_mm_takedown(&dev->offset_manager);
return -ENOMEM;
+ }
INIT_LIST_HEAD(&dev->maplist->head);

/* the DRM has 6 counters */
@@ -113,10 +114,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,

dev->driver = driver;

- if (dev->driver->load)
- if ((retcode = dev->driver->load(dev, ent->driver_data)))
- goto error_out_unreg;
-
if (drm_core_has_AGP(dev)) {
if (drm_device_is_agp(dev))
dev->agp = drm_agp_init(dev);
@@ -136,6 +133,10 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
}
}

+ if (dev->driver->load)
+ if ((retcode = dev->driver->load(dev, ent->driver_data)))
+ goto error_out_unreg;
+
retcode = drm_ctxbitmap_init(dev);
if (retcode) {
DRM_ERROR("Cannot allocate memory for context bitmap.\n");

linux-core/drm_vm.c +0 -0
index b887153..1f905fb 100644
@@ -516,7 +516,8 @@ static int drm_mmap_dma(struct file *filp, struct 

vm_area_struct *vma)
return -EINVAL;
}

- if (!capable(CAP_SYS_ADMIN) && (dma->flags & _DRM_DMA_USE_PCI_RO)) {
+ if (!capable(CAP_SYS_ADMIN) &&
+ (dma->flags & _DRM_DMA_USE_PCI_RO)) {
vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
#if defined(__i386__) || defined(__x86_64__)
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
@@ -738,7 +739,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
unsigned long bus_base;
unsigned long bus_offset;
unsigned long bus_size;
- unsigned long ret = NOPFN_REFAULT;
+ int ret = NOPFN_REFAULT;

if (address > vma->vm_end)
return NOPFN_SIGBUS;

#14 lore raw

Re: [PATCH 2/3] drm modesetting core

Quoted 8 lines · Jesse Barnes

This patch adds the core of the new DRM based modesetting system. It creates several new structures in the DRM, the primary ones being the CRTC, which controls all aspects of your device's CRTC(s), output, which describes and controls the various outputs on your gfx chip (e.g. TMDS, LVDS, VGA, etc.), and mode, which describes graphics modes in enough detail for the output and CRTC callbacks to program them to hardware.

Quoted 5 lines

It also contains the user level IOCTL interfaces for doing graphics programming (getting CRTC, output and mode lists, setting up new frame buffer objects, etc.).

It relies on the new TTM patch Dave posted recently.

 Makefile.kernel |    6
 drmP.h          |   11
 drm_bo.c        |    8
 drm_bo_move.c   |    2
 drm_bufs.c      |    3
 drm_compat.h    |    7
 drm_crtc.c      | 1652 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drm_crtc.h      |  535 ++++++++++++++++++
 drm_drv.c       |   92 ---
 drm_edid.c      |  467 +++++++++++++++
 drm_edid.h      |  176 +++++
 drm_fb.c        |  201 ++++++
 drm_fops.c      |    4
 drm_modes.c     |  558 ++++++++++++++++++
 drm_objects.h   |   22
 drm_os_linux.h  |   18
 drm_stub.c      |   21
 drm_vm.c        |    5
 18 files changed, 3695 insertions(+), 93 deletions(-)
#15 lore raw

Re: [PATCH 2/3] drm modesetting core

In reply to Jesse Barnes

Il Thu, May 17, 2007 at 03:37:45PM -0700, Jesse Barnes ha scritto:

Quoted 1 line

This patch adds the core of the new DRM based modesetting system.

A couple of comments on drm_fb since I'm somewhat familiar with fb code:

Quoted 10 lines

new file mode 100644
index 0000000..0d06792

linux-core/drm_edid.c new file +5 -0
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <[email protected]>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) 
Quoted 2 lines

originally from
+ * FB layer.

Hum, why are you duplicating them here? fbmon.c has the infrastructure for parsing and even fixing known-broken EDIDs.

Quoted 34 lines

+ * Copyright (C) 2006 Dennis Munsie <[email protected]>
+ */

linux-core/drm_edid.c new file +7 -0
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/* Valid EDID header has these bytes */
+static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 

0x00 };

linux-core/drm_edid.c new file +6 -0
+
+/**
+ * edid_valid - sanity check EDID data
+ * @edid: EDID data
+ *
+ * Sanity check the EDID block by looking at the header, the version 

number
+ * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
+ * valid.
+ */

linux-core/drm_edid.c new file +13 -0
+static bool edid_valid(struct edid *edid)
+{
+	int i;
+	u8 csum = 0;
+	u8 *raw_edid = (u8 *)edid;
+
+	if (memcmp(edid->header, edid_header, sizeof(edid_header)))
+		goto bad;
+	if (edid->version != 1)
+		goto bad;
+	if (edid->revision <= 0 || edid->revision > 3)
+		goto bad;
+

linux-core/drm_edid.c

Quoted 10 lines
linux-core/drm_edid.c new file +10 -0
+	for (i = 0; i < EDID_LENGTH; i++)
+		csum += raw_edid[i];
+	if (csum)
+		goto bad;
+
+	return 1;
+
+bad:
+	return 0;
+}

This is basically edid_check_header + edid_checksum.

Quoted 14 lines
linux-core/drm_edid.c new file +3 -0
+
+/**
+ * drm_mode_std - convert standard mode info (width, height, refresh) 

into mode
+ * @t: standard timing params
+ *
+ * Take the standard timing params (in this case width, aspect, and refresh)
+ * and convert them into a real mode using CVT.
+ *
+ * Punts for now, but should eventually use the FB layer's CVT based mode
+ * generation code.
+ */

linux-core/drm_edid.c

Quoted 3 lines
linux-core/drm_edid.c new file +3 -0
+struct drm_display_mode *drm_mode_std(struct drm_device *dev,
+				      struct std_timing *t)
+{

get_std_timing?

Quoted 14 lines

+/**
+ * drm_mode_detailed - create a new mode from an EDID detailed timing section
+ * @timing: EDID detailed timing info
+ * @preferred: is this a preferred mode?
+ *
+ * An EDID detailed timing block contains enough info for us to create and
+ * return a new struct drm_display_mode. The @preferred flag will be set
+ * if this is the display's preferred timing, and we'll use it to indicate
+ * to the other layers that this mode is desired.
+ */

linux-core/drm_edid.c

Quoted 3 lines
linux-core/drm_edid.c new file +3 -0
+struct drm_display_mode *drm_mode_detailed(drm_device_t *dev,
+					   struct detailed_timing *timing)
+{

get_detailed_timing?

If you can't use 'struct fb_videomode' we may refactor code around a common data structure instead of a copy&paste.

Quoted 2 lines

+static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)

[...]

Quoted 1 line

+static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)

[...]

Copy and paste from fb_dcc.c; furthermore a fix in drm_ddc_read hasn't been backported to the original code.

Quoted 125 lines
linux-core/drm_fb.c new file +4 -0
new file mode 100644
index 0000000..ef05341
@@ -0,0 +1,201 @@
+/*
+ * Copyright © 2007 David Airlie
+ *
+ * Permission is hereby granted, free of charge, to any person 

obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * David Airlie
+ */

linux-core/drm_fb.c new file +22 -0
+    /*
+     *  Modularization
+     */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+struct drmfb_par {
+	struct drm_device *dev;
+	struct drm_framebuffer *fb;
+};
+
+static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned 

green,

linux-core/drm_fb.c new file +59 -0
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	struct drmfb_par *par = info->par;
+	struct drm_framebuffer *fb = par->fb;
+	if (regno > 17)
+		return 1;
+
+	if (regno < 16) {
+		switch (fb->depth) {
+		case 15:
+			fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+				((green & 0xf800) >>  6) |
+				((blue & 0xf800) >> 11);
+			break;
+		case 16:
+			fb->pseudo_palette[regno] = (red & 0xf800) |
+				((green & 0xfc00) >>  5) |
+				((blue  & 0xf800) >> 11);
+			break;
+		case 24:
+		case 32:
+			fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+				(green & 0xff00) |
+				((blue  & 0xff00) >> 8);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* this will let fbcon do the mode init */
+static int drmfb_set_par(struct fb_info *info)
+{
+	struct drmfb_par *par = info->par;
+	struct drm_device *dev = par->dev;
+
+	drm_set_desired_modes(dev);
+	return 0;
+}
+
+static struct fb_ops drmfb_ops = {
+	.owner = THIS_MODULE,
+	//	.fb_open = drmfb_open,
+	//	.fb_read = drmfb_read,
+	//	.fb_write = drmfb_write,
+	//	.fb_release = drmfb_release,
+	//	.fb_ioctl = drmfb_ioctl,
+	.fb_set_par = drmfb_set_par,
+	.fb_setcolreg = drmfb_setcolreg,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+};
+
+int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
+{
+	struct fb_info *info;

linux-core/drm_fb.c

Quoted 10 lines
linux-core/drm_fb.c new file +10 -0
+	struct drmfb_par *par;
+	struct device *device = &dev->pdev->dev; 
+	struct fb_var_screeninfo *var_info;
+	unsigned long base, size;
+	int ret;
+
+	info = framebuffer_alloc(sizeof(struct drmfb_par), device);
+	if (!info){
+		return -EINVAL;
+	}

-ENOMEM? Plus, spurious brackets.

linux-core/drm_fb.c

Quoted 2 lines
linux-core/drm_fb.c new file +2 -0
+	if (register_framebuffer(info) < 0)
+		return -EINVAL;

You leak the fb_info structure on error path.

linux-core/drm_fb.c

Quoted 6 lines
linux-core/drm_fb.c new file +6 -0
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+	       info->fix.id);
+	return 0;
+}
+EXPORT_SYMBOL(drmfb_probe);

Luca

Signature · 2 lines
Software is like sex; it's better when it's free.
Linus Torvalds
#16 lore raw

Re: [PATCH 2/3] drm modesetting core

Quoted 4 lines · Luca Tettamanti

Il Thu, May 17, 2007 at 03:37:45PM -0700, Jesse Barnes ha scritto:

Quoted 1 line

This patch adds the core of the new DRM based modesetting system.

A couple of comments on drm_fb since I'm somewhat familiar with fb code:

Quoted 15 lines
Quoted 10 lines

new file mode 100644
index 0000000..0d06792

linux-core/drm_edid.c new file +5 -0
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <[email protected]>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid)
Quoted 2 lines

originally from
+ * FB layer.

Hum, why are you duplicating them here? fbmon.c has the infrastructure for parsing and even fixing known-broken EDIDs.

Yeah, there's more sharing that could be done... though I don't think the fb layer has the bits to actually grab EDIDs. Also, DRM is shared with BSD...

Quoted 17 lines
Quoted 17 lines
linux-core/drm_edid.c new file +17 -0
+static bool edid_valid(struct edid *edid)
+{
+	int i;
+	u8 csum = 0;
+	u8 *raw_edid = (u8 *)edid;
+
+	if (memcmp(edid->header, edid_header, sizeof(edid_header)))
+		goto bad;
+	if (edid->version != 1)
+		goto bad;
+	if (edid->revision <= 0 || edid->revision > 3)
+		goto bad;
+
+	for (i = 0; i < EDID_LENGTH; i++)
+		csum += raw_edid[i];
+	if (csum)
+		goto bad;
Quoted 8 lines

linux-core/drm_edid.c

Quoted 6 lines
linux-core/drm_edid.c new file +6 -0
+
+	return 1;
+
+bad:
+	return 0;
+}

This is basically edid_check_header + edid_checksum.

Yep, pretty trivial stuff.

Quoted 4 lines

get_detailed_timing?

If you can't use 'struct fb_videomode' we may refactor code around a common data structure instead of a copy&paste.

I agree that would be better. I'll see what I can do to unify the two.

Quoted 11 lines
Quoted 2 lines

+static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)

[...]

Quoted 1 line

+static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)

[...]

Copy and paste from fb_dcc.c; furthermore a fix in drm_ddc_read hasn't been backported to the original code.

I think the original tries a few times... but it's still buggy. I've got an old EDID 1.1 monitor whose EDID block is fetched by X but not by this code (or the original FB code) so I think we still have some timing bugs to fix.

Quoted 6 lines

linux-core/drm_edid.c

Quoted 4 lines
linux-core/drm_edid.c new file +4 -0
+	info = framebuffer_alloc(sizeof(struct drmfb_par), device);
+	if (!info){
+		return -EINVAL;
+	}

-ENOMEM? Plus, spurious brackets.

Fixed, thanks.

Quoted 4 lines

linux-core/drm_edid.c

Quoted 2 lines
linux-core/drm_edid.c new file +2 -0
+	if (register_framebuffer(info) < 0)
+		return -EINVAL;

You leak the fb_info structure on error path.

Oops, I'll fix that too.

At this point though, the drm_fb driver isn't actually used. I recently added the intel_fb driver (mostly using code from intelfb) so we could have an accelerated DRM FB driver, hopefully that one's ok.

Thanks for looking at it.

Jesse

#17 lore raw

Re: [PATCH 2/3] drm modesetting core

Il Thu, May 17, 2007 at 06:04:54PM -0700, Jesse Barnes ha scritto:

Quoted 21 lines · Luca Tettamanti
Quoted 4 lines

Il Thu, May 17, 2007 at 03:37:45PM -0700, Jesse Barnes ha scritto:

Quoted 1 line

This patch adds the core of the new DRM based modesetting system.

A couple of comments on drm_fb since I'm somewhat familiar with fb code:

Quoted 15 lines
Quoted 10 lines

new file mode 100644
index 0000000..0d06792

linux-core/drm_edid.c new file +5 -0
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <[email protected]>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid)
Quoted 2 lines

originally from
+ * FB layer.

Hum, why are you duplicating them here? fbmon.c has the infrastructure for parsing and even fixing known-broken EDIDs.

Quoted 2 lines

Yeah, there's more sharing that could be done... though I don't think the fb layer has the bits to actually grab EDIDs.

There are the I2C functions (fb_do_probe_ddc_edid, fb_ddc_read - I wrote them for the radeon driver, but now are available for general use) which will issue the read command; fbmon.c has the stuff for parsing the EDID; you usualy build a DB of supported modes which is then used to validate the mode requested by the user. Of course each driver has to implement the I2C adapter.

Quoted 1 line

Also, DRM is shared with BSD...

Your patch already uses 'struct i2c_adapter' in drm_edid.c, is it portable?

Luca

Signature · 2 lines
"Vorrei morire ucciso dagli agi. Vorrei che di me si dicesse: ``Com'è
morto?'' ``Gli è scoppiato il portafogli''" -- Marcello Marchesi
#18 lore raw

Re: [PATCH 2/3] drm modesetting core

Quoted 9 lines · Luca Tettamanti
Quoted 2 lines

Yeah, there's more sharing that could be done... though I don't think the fb layer has the bits to actually grab EDIDs.

There are the I2C functions (fb_do_probe_ddc_edid, fb_ddc_read - I wrote them for the radeon driver, but now are available for general use) which will issue the read command; fbmon.c has the stuff for parsing the EDID; you usualy build a DB of supported modes which is then used to validate the mode requested by the user. Of course each driver has to implement the I2C adapter.

I'll take a look at fbmon... I've seen the fb_ddc_read stuff but didn't see many drivers using it heavily. I think it makes sense to reuse your code where possible (in fact some earlier versions of the code made more use of FB stuff but was removed or rewritten for various reasons).

Quoted 4 lines
Quoted 1 line

Also, DRM is shared with BSD...

Your patch already uses 'struct i2c_adapter' in drm_edid.c, is it portable?

I'm not sure how portable that will be. But regardless, if Linux has some of this code already, I'd like to reuse it. I'll go head and see what I can rip out.

In fact, I've received some comments pushing me towards moving the core code (crtc, mode management) to drivers/video instead of DRM. That might make sense, especially if we can just use/extend the FB layer's mode tracking structures.

Thanks,
Jesse

#19 lore raw

PATCH 3/3 Intel support for DRM modesetting

In reply to Jesse Barnes

This patch adds support for DRM modesetting to the Intel DRM driver and stubs out a simple FB driver to sit underneath. The code had to be refactored a bit, since current DRM drivers tend to be fully initialized by userspace via ioctls. This patch makes the driver load routine do most of the heavy lifting, since it's necessary in order to fully bring up a console driver.

It also relies on the TTM patch Dave posted recently for allocating the initial framebuffer used by the FB layer.

Jesse

linux-core/i915_drv.c +1 -1
index 7fdb083..50ff977 100644
@@ -79,7 +79,7 @@ static struct drm_driver driver = {
 	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
 	    DRIVER_IRQ_VBL2,
 	.load = i915_driver_load,
-	.firstopen = i915_driver_firstopen,
+	.unload = i915_driver_unload,
 	.lastclose = i915_driver_lastclose,
 	.preclose = i915_driver_preclose,
 	.device_is_agp = i915_driver_device_is_agp,
linux-core/i915_init.c new file +305 -0

305 lines not on this page · raw message

linux-core/intel_crt.c new file +248 -0

248 lines not on this page · raw message

linux-core/intel_display.c new file +1232 -0

1,232 lines not on this page · raw message

linux-core/intel_drv.h new file +79 -0

79 lines not on this page · raw message

linux-core/intel_i2c.c new file +187 -0

187 lines not on this page · raw message

linux-core/intel_lvds.c new file +500 -0

500 lines not on this page · raw message

linux-core/intel_modes.c new file +55 -0

55 lines not on this page · raw message

linux-core/intel_sdvo.c new file +1095 -0

386 lines not on this page · raw message

linux-core/intel_sdvo_regs.h new file +328 -0

328 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#20 lore raw

Re: [PATCH 3/3] Intel support for DRM modesetting

Quoted 9 lines · Jesse Barnes

This patch adds support for DRM modesetting to the Intel DRM driver and stubs out a simple FB driver to sit underneath. The code had to be refactored a bit, since current DRM drivers tend to be fully initialized by userspace via ioctls. This patch makes the driver load routine do most of the heavy lifting, since it's necessary in order to fully bring up a console driver.

It also relies on the TTM patch Dave posted recently for allocating the initial framebuffer used by the FB layer.

 i915_drv.c        |    2
 i915_init.c       |  305 +++++++++++++
 intel_crt.c       |  248 ++++++++++
 intel_display.c   | 1232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 intel_drv.h       |   79 +++
 intel_i2c.c       |  187 ++++++++
 intel_lvds.c      |  500 +++++++++++++++++++++
 intel_modes.c     |   55 ++
 intel_sdvo.c      | 1095 +++++++++++++++++++++++++++++++++++++++++++++++
 intel_sdvo_regs.h |  328 ++++++++++++++
 10 files changed, 4030 insertions(+), 1 deletion(-)
#21 lore raw
In reply to Jesse Barnes
Quoted 4 lines · Jesse Barnes

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

How is supporting different users logged into each head going to work? The original model for this was to give each head its own fbdev device. It is important that each user be able to set their own mode without being root.

Jon Smirl
[email protected]

#22 lore raw
Quoted 10 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

How is supporting different users logged into each head going to work? The original model for this was to give each head its own fbdev device. It is important that each user be able to set their own mode without being root.

With the interfaces implemented here, a userspace application can create a multiseat environment either with a single graphics card with multiple outputs or multiple cards. It could do this by creating several frame buffer objects and associating them with whatever CRTCs were available, and managing input via existing APIs. I don't know of anyone that's done this yet though...

Jesse

#23 lore raw
Quoted 6 lines · Jesse Barnes

With the interfaces implemented here, a userspace application can create a multiseat environment either with a single graphics card with multiple outputs or multiple cards. It could do this by creating several frame buffer objects and associating them with whatever CRTCs were available, and managing input via existing APIs. I don't know of anyone that's done this yet though...

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

By making one device per head it becomes possible to assign ownership of the device to the specific user and let them do whatever they want to it. It's then up to the device driver to sort everything out. fbdev has already been designed with this in mind and I believe the Matrox driver implements it. This model easily expands from one to N heads.

Merged-fb modes are handled by including them in the allowable modes list on both heads. If you own both heads you can set a merged-fb mode and the other device will just return EBUSY.

How are you reconciling the introduction of a new mode setting API with the 90 existing fbdev drivers? We clearly don't want two competing APIs in the kernel. What's the plan for converting all of the existing drivers?

Signature · 2 lines
Jon Smirl
[email protected]
#24 lore raw
Quoted 6 lines · Jon Smirl

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

If you have multiple "controlling" apps competing for a single device, that either implies complexity in each app for sharing control, or moving even more code into the kernel for 2D and 3D.

I don't think the kernel community is yet interested in moving everything of consequence into the kernel.

Jeff

#25 lore raw
Quoted 9 lines · Jeff Garzik
Quoted 6 lines · Jon Smirl

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

Quoted 6 lines

If you have multiple "controlling" apps competing for a single device, that either implies complexity in each app for sharing control, or moving even more code into the kernel for 2D and 3D.

I don't think the kernel community is yet interested in moving everything of consequence into the kernel.

Before dismissing this you might want to spend some time designing it.

When I said head I should have been more specific and said CRTC. CRTCs are pretty much independent from each other and can be assigned one per device. I believe this has already been done in the Matrox fbdev driver. I have also prototyped this on the Radeon hardware and it works. It is how fbdev was designed to work. As for 3D support, making 3D work on a per user basis is not very different from the way direct rendering works today.

Supporting multiple users, one on each CRTC, has long been a feature request from people building low end educational systems, kiosks, Internet cafes, etc. If the entire graphics subsystem is going to get rewritten this feature should be added.

After designing this I think you will find that the extra code that needs to go into the kernel is minimal. You have to split the video memory into multiple pools and keep people from accessing queues that they don't own. Code like this is supposed to be in the kernel.

Having a multi-megabyte root priv graphics process always running is a scary security exposure. This privileged process is not necessary and through proper design it can be eliminated. After designing this I think you'll find that less than 1% of the code ends up in the driver and the rest can run unprivileged in user space. Put the root priv code into the device driver where it will get the scrutiny it needs.

Quoted 5 lines

Jeff

Signature · 2 lines
Jon Smirl
[email protected]
#26 lore raw
Quoted 4 lines · Jon Smirl

Supporting multiple users, one on each CRTC, has long been a feature request from people building low end educational systems, kiosks, Internet cafes, etc. If the entire graphics subsystem is going to get rewritten this feature should be added.

are you going to write the code?

this topic has been on the table for YEARS and no code appeared. The patch here is a great step forward for the common case, and seems to allow more complex setups either already or with some minor future modifications.... so how about we move forward with this code that exists today, instead of doing more vaporware while holding the rest of the world back...

#27 lore raw
In reply to Jon Smirl
Quoted 8 lines · Jon Smirl
Quoted 6 lines · Jesse Barnes

With the interfaces implemented here, a userspace application can create a multiseat environment either with a single graphics card with multiple outputs or multiple cards. It could do this by creating several frame buffer objects and associating them with whatever CRTCs were available, and managing input via existing APIs. I don't know of anyone that's done this yet though...

Quoted 6 lines

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

Even without a graphics server of some sort arbitrating access (and it doesn't have to be a big as the current X server btw), you'd still need your apps to take a card specific lock and/or coordinate so that they don't clobber one another's rendering results. This could be done in the kernel, but for many devices the complexity added is likely to be pretty high.

OTOH, if you're just talking about mapping sections of VRAM to user level processes to manage as indpendent heads, that's fairly trivial to do as you say, but you'd almost certainly want acceleration for any sort of real world application, which is where things would get tricky.

Quoted 4 lines

How are you reconciling the introduction of a new mode setting API with the 90 existing fbdev drivers? We clearly don't want two competing APIs in the kernel. What's the plan for converting all of the existing drivers?

My initial plan was to only convert drivers to this new API if they had hardware that justified a DRM driver (i.e. high performance devices with command ring buffers, 3D, etc.), and leave the other FB drivers alone, since the FB layer is quite suited to simple devices.

The other option of course is to port the existing drivers over to the new modesetting interfaces, though I suspect in many cases that may not be particularly useful. I'm open to suggestions.

Thanks,
Jesse

#28 lore raw
Quoted 16 lines · Jesse Barnes
Quoted 8 lines · Jon Smirl
Quoted 6 lines · Jesse Barnes

With the interfaces implemented here, a userspace application can create a multiseat environment either with a single graphics card with multiple outputs or multiple cards. It could do this by creating several frame buffer objects and associating them with whatever CRTCs were available, and managing input via existing APIs. I don't know of anyone that's done this yet though...

Quoted 6 lines

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

Quoted 6 lines

Even without a graphics server of some sort arbitrating access (and it doesn't have to be a big as the current X server btw), you'd still need your apps to take a card specific lock and/or coordinate so that they don't clobber one another's rendering results. This could be done in the kernel, but for many devices the complexity added is likely to be pretty high.

We have already have the card specific locks, it's how Direct Rendering works.

Besides, card locks are a much better design that the free for all that happens on a VT switch.

Quoted 10 lines

OTOH, if you're just talking about mapping sections of VRAM to user level processes to manage as indpendent heads, that's fairly trivial to do as you say, but you'd almost certainly want acceleration for any sort of real world application, which is where things would get tricky.

Quoted 4 lines

How are you reconciling the introduction of a new mode setting API with the 90 existing fbdev drivers? We clearly don't want two competing APIs in the kernel. What's the plan for converting all of the existing drivers?

Quoted 8 lines

My initial plan was to only convert drivers to this new API if they had hardware that justified a DRM driver (i.e. high performance devices with command ring buffers, 3D, etc.), and leave the other FB drivers alone, since the FB layer is quite suited to simple devices.

The other option of course is to port the existing drivers over to the new modesetting interfaces, though I suspect in many cases that may not be particularly useful. I'm open to suggestions.

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

If the kernel graphics system is going to get rewritten the rewrite needs to address all of the existing problems.

Signature · 2 lines
Jon Smirl
[email protected]
#29 lore raw
Quoted 24 lines · Jon Smirl
Quoted 16 lines · Jesse Barnes
Quoted 8 lines · Jon Smirl
Quoted 6 lines · Jesse Barnes

With the interfaces implemented here, a userspace application can create a multiseat environment either with a single graphics card with multiple outputs or multiple cards. It could do this by creating several frame buffer objects and associating them with whatever CRTCs were available, and managing input via existing APIs. I don't know of anyone that's done this yet though...

Quoted 6 lines

This design still requires a global server app since the heads share a single device.
I am always concerned that the root priv code in the X server is a potential security hole. I would like to move away from a model where there is a global controlling app. I don't think we need a global controlling app at all.

Quoted 6 lines

Even without a graphics server of some sort arbitrating access (and it doesn't have to be a big as the current X server btw), you'd still need your apps to take a card specific lock and/or coordinate so that they don't clobber one another's rendering results. This could be done in the kernel, but for many devices the complexity added is likely to be pretty high.

Quoted 5 lines

We have already have the card specific locks, it's how Direct Rendering works.

Besides, card locks are a much better design that the free for all that happens on a VT switch.

Right, I'm just saying there's much more to it than just having the hardware locks (which of course we already have).

Quoted 5 lines

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

Maybe you should take a look at the patches. :) The code I posted actually creates an fb device as a slave of the DRM device, and uses that for the boot console. Once you've booted, you can use the new interfaces to do whatever you want with the graphics device... though it doesn't create /dev/fb* devices per-CRTC like you seem to want, it's really easy to do the equivalent with a small userspace program (though I haven't actually tested sharing of buffer objects, it should work).

Quoted 2 lines

If the kernel graphics system is going to get rewritten the rewrite needs to address all of the existing problems.

Sure, I have no problem with that, but there are usually lots of ways to solve a given problem.

Jesse

#30 lore raw
Quoted 6 lines · Jesse Barnes
Quoted 5 lines

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

Quoted 7 lines

Maybe you should take a look at the patches. :) The code I posted actually creates an fb device as a slave of the DRM device, and uses that for the boot console. Once you've booted, you can use the new interfaces to do whatever you want with the graphics device... though it doesn't create /dev/fb* devices per-CRTC like you seem to want, it's really easy to do the equivalent with a small userspace program (though I haven't actually tested sharing of buffer objects, it should work).

Actually, scratch that last bit. I forgot about a recent change alanh committed that did just that: per-CRTC FB devices. So please take a close look (modesetting-101 of mesa/drm git at freedesktop.org) and let me know if you see any gaping holes.

Thanks,
Jesse

#31 lore raw
Quoted 15 lines · Jesse Barnes
Quoted 6 lines · Jesse Barnes
Quoted 5 lines

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

Quoted 7 lines

Maybe you should take a look at the patches. :) The code I posted actually creates an fb device as a slave of the DRM device, and uses that for the boot console. Once you've booted, you can use the new interfaces to do whatever you want with the graphics device... though it doesn't create /dev/fb* devices per-CRTC like you seem to want, it's really easy to do the equivalent with a small userspace program (though I haven't actually tested sharing of buffer objects, it should work).

Quoted 4 lines

Actually, scratch that last bit. I forgot about a recent change alanh committed that did just that: per-CRTC FB devices. So please take a close look (modesetting-101 of mesa/drm git at freedesktop.org) and let me know if you see any gaping holes.

Here are some of the goals that I believe a rewrite of the graphics system should address:

1) Be upwards compatible with the existing fbdev drivers. This lets us avoid rewriting the 90 existing drivers. New drivers shouldn't break any old apps.

2) Address the long outstanding issue of multi-seat at the console level. My solution to this is the one device per CRTC model.

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

4) OOPS should always display even if in a graphics mode

5) Support Secure Attention Key (SAK).

6) Eliminate the existing VT swap driver free for all. I would compile out the VT layer and replace it with a compatible API that enforces some sanity.

7) Support Unicode on the console

8) Allow multiple user space graphics systems to run. These user space systems should not touch the hardware, instead they ask the kernel driver to manipulate the hardware on their behalf. Of course the kernel driver is only the minimum code needed to arbitrate control of the resources - it doesn't do things like implement drawing algorithms.

9) Booting on non-VGA hardware still needs to work.

10) Support things like cloning and output device selection.

Of course a driver doesn't need to support all of this in its first release. What's important is that the new architecture support all of these features so that we don't end up rearchitecting it yet again.

Other people may add more things to this list. Let's get the design right this time around and address all of the known problems.

Signature · 2 lines
Jon Smirl
[email protected]
#32 lore raw
Quoted 5 lines

1) Be upwards compatible with the existing fbdev drivers. This lets us avoid rewriting the 90 existing drivers. New drivers shouldn't break any old apps.

done.

Quoted 2 lines

2) Address the long outstanding issue of multi-seat at the console level. My solution to this is the one device per CRTC model.

done.

Quoted 3 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

Stupid idea, we need something to control policy, this isn't going in the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

Quoted 1 line

4) OOPS should always display even if in a graphics mode

possible to do.

Quoted 2 lines

5) Support Secure Attention Key (SAK).

possible to do.

Quoted 3 lines

6) Eliminate the existing VT swap driver free for all. I would compile out the VT layer and replace it with a compatible API that enforces some sanity.

I'm hoping to look into this but it is a parallel problem to what this code does, the VT switch API sucks rocks, so providing something compatible is going to suck rocks..

Quoted 1 line

7) Support Unicode on the console

This just needs a userspace console again a parallel problem that really isn't much to do with the problem set this work is trying to solve... it should enable it...

Quoted 7 lines

8) Allow multiple user space graphics systems to run. These user space systems should not touch the hardware, instead they ask the kernel driver to manipulate the hardware on their behalf. Of course the kernel driver is only the minimum code needed to arbitrate control of the resources - it doesn't do things like implement drawing algorithms.

No problems.

Quoted 5 lines

9) Booting on non-VGA hardware still needs to work.

10) Support things like cloning and output device selection.

No problems.

Dave.

#33 lore raw
Quoted 6 lines · Dave Airlie
Quoted 2 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

Stupid idea, we need something to control policy, this isn't going in the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

Try to be more flexible with your thinking. It is ok to have a transient, privileged command line app that does something like assign an output to be under the control of a specific CRTC. I have no problem with some of the IOCTLs requiring root priv.

What is not ok is to require a permanently running root priv process. If the code is going to always be running make it as small as possible and put it in the device driver.

Signature · 2 lines
Jon Smirl
[email protected]
#34 lore raw
In reply to Dave Airlie
Quoted 3 lines · Dave Airlie

This just needs a userspace console again a parallel problem that really isn't much to do with the problem set this work is trying to solve... it should enable it...

When I went through the design process for all this I came to the same conclusion about needing a user space console process.

User space console does impact on all of this because it implies that the current console should be be defeatured down until it becomes only a system recovery console and not a console for everyday use.

For example, one part of the defeaturing would be to remove the drawing acceleration code in the existing fbdev console drivers and to rework it to support accelerated drawing from the user space console implementation. You want the system recovery console mode to be as simple as possible so that it is always guaranteed to work. User space console is also what leads to the idea of compiling VT out of the kernel.

Once you decide that a user space console is needed then the per CRTC device node becomes more obvious since different people can be logged onto the different consoles.

All of the points in the list are interrelated and the architecture needs to address everything as a unified whole.

Signature · 2 lines
Jon Smirl
[email protected]
#35 lore raw
Quoted 20 lines · Jon Smirl
Quoted 3 lines · Dave Airlie

This just needs a userspace console again a parallel problem that really isn't much to do with the problem set this work is trying to solve... it should enable it...

When I went through the design process for all this I came to the same conclusion about needing a user space console process.

User space console does impact on all of this because it implies that the current console should be be defeatured down until it becomes only a system recovery console and not a console for everyday use.

For example, one part of the defeaturing would be to remove the drawing acceleration code in the existing fbdev console drivers and to rework it to support accelerated drawing from the user space console implementation. You want the system recovery console mode to be as simple as possible so that it is always guaranteed to work. User space console is also what leads to the idea of compiling VT out of the kernel.

Quoted 6 lines

Once you decide that a user space console is needed then the per CRTC device node becomes more obvious since different people can be logged onto the different consoles.

All of the points in the list are interrelated and the architecture needs to address everything as a unified whole.

you were doing fine up until the last point, they are interrelated but not architecturally dependent, we can do a lot of work on this stuff without that, we don't need to deprecate anything, just provide new interfaces that new drivers can use to implement this stuff, then people can pull over the old drivers at their own pace, like we can just stick a flag in the console that says we can handle things like dumping oopsen in KD_GRAPHICS etc.. drivers that can do it will do it, drivers that can't won't.

You don't compile VT out you just disable it when you have a driver that supports the model,

You also require a heavy weight state switch for suspend/resume in any case so this could be utilised for other things, e.g. text mode on many cards can't be done while acceleration is operational, but certainly don't want to bar text mode for people who want it..

Dave.

#36 lore raw
Quoted 28 lines · Dave Airlie
Quoted 20 lines · Jon Smirl
Quoted 3 lines · Dave Airlie

This just needs a userspace console again a parallel problem that really isn't much to do with the problem set this work is trying to solve... it should enable it...

When I went through the design process for all this I came to the same conclusion about needing a user space console process.

User space console does impact on all of this because it implies that the current console should be be defeatured down until it becomes only a system recovery console and not a console for everyday use.

For example, one part of the defeaturing would be to remove the drawing acceleration code in the existing fbdev console drivers and to rework it to support accelerated drawing from the user space console implementation. You want the system recovery console mode to be as simple as possible so that it is always guaranteed to work. User space console is also what leads to the idea of compiling VT out of the kernel.

Quoted 6 lines

Once you decide that a user space console is needed then the per CRTC device node becomes more obvious since different people can be logged onto the different consoles.

All of the points in the list are interrelated and the architecture needs to address everything as a unified whole.

Quoted 8 lines

you were doing fine up until the last point, they are interrelated but not architecturally dependent, we can do a lot of work on this stuff without that, we don't need to deprecate anything, just provide new interfaces that new drivers can use to implement this stuff, then people can pull over the old drivers at their own pace, like we can just stick a flag in the console that says we can handle things like dumping oopsen in KD_GRAPHICS etc.. drivers that can do it will do it, drivers that can't won't.

You are describing a transition plan without knowing what the final design is going to look like. We really need to hash out the final design so that the right path is taken to get there.

For example I didn't have per CRTC device nodes or user space consoles in my original design, but after talking to some of the people that really wanted the multi-seat feature it led me down the user space console path and to the per CRTC device node solution. I also got beat up at OLS by people wanting full Unicode support on the console.

Quoted 11 lines

You don't compile VT out you just disable it when you have a driver that supports the model,

You also require a heavy weight state switch for suspend/resume in any case so this could be utilised for other things, e.g. text mode on many cards can't be done while acceleration is operational, but certainly don't want to bar text mode for people who want it..

Dave.

Signature · 2 lines
Jon Smirl
[email protected]
#37 lore raw
Quoted 11 lines

You are describing a transition plan without knowing what the final design is going to look like. We really need to hash out the final design so that the right path is taken to get there.

For example I didn't have per CRTC device nodes or user space consoles in my original design, but after talking to some of the people that really wanted the multi-seat feature it led me down the user space console path and to the per CRTC device node solution. I also got beat up at OLS by people wanting full Unicode support on the console.

No we are defining steps towards improving the drivers on Linux, the first step is the requirement to fix suspend/resume, and allow modesetting on multiple crtc/output combinations, the other goals are not directly within the scope of this work, you can take steps to do get where we want, but we don't need to move all drivers at once to get there... we also can't just merge something like that to the kernel...

Your old ideas were mostly limited by the fact that you didn't get the crtc/output distinction and persisted with the idea of heads which put policy in the kernel, this was a major failing you never discovered, and I didn't probably look enough at the time, since then Keith Packard has done a lot of work on randr 1.2 to show the path to what we actually wanted.

Dave.

#38 lore raw
Quoted 20 lines · Dave Airlie
Quoted 11 lines

You are describing a transition plan without knowing what the final design is going to look like. We really need to hash out the final design so that the right path is taken to get there.

For example I didn't have per CRTC device nodes or user space consoles in my original design, but after talking to some of the people that really wanted the multi-seat feature it led me down the user space console path and to the per CRTC device node solution. I also got beat up at OLS by people wanting full Unicode support on the console.

No we are defining steps towards improving the drivers on Linux, the first step is the requirement to fix suspend/resume, and allow modesetting on multiple crtc/output combinations, the other goals are not directly within the scope of this work, you can take steps to do get where we want, but we don't need to move all drivers at once to get there... we also can't just merge something like that to the kernel...

Quoted 6 lines

Your old ideas were mostly limited by the fact that you didn't get the crtc/output distinction and persisted with the idea of heads which put policy in the kernel, this was a major failing you never discovered, and I didn't probably look enough at the time, since then Keith Packard has done a lot of work on randr 1.2 to show the path to what we actually wanted.

I thought Luc Verhaegen figured that out not Keith.

Call it whatever you want and I have wasted far too much time arguing with you and Keith and I can never get agreement on anything. BTW, should I search the LKML archives and find the messages where you call me stupid and block my patches merging fbdev/DRM? That's effectively what you are doing right now.

There is a significant group of Linux users who want to be able to login separate users to each screen/head/crtc/output device. These people are concentrated in the third world and don't show up at OLS to argue their case.

There is another group that wants Unicode consoles. The people I talked to were from India and Japan.

I am not a member of either group. So go ahead and ignore me, I'd just like to see these two groups get features implemented that have been ignored for a long time.

Quoted 3 lines

Dave.

Signature · 2 lines
Jon Smirl
[email protected]
#39 lore raw
Quoted 21 lines · Jon Smirl
Quoted 20 lines · Dave Airlie
Quoted 11 lines

You are describing a transition plan without knowing what the final design is going to look like. We really need to hash out the final design so that the right path is taken to get there.

For example I didn't have per CRTC device nodes or user space consoles in my original design, but after talking to some of the people that really wanted the multi-seat feature it led me down the user space console path and to the per CRTC device node solution. I also got beat up at OLS by people wanting full Unicode support on the console.

No we are defining steps towards improving the drivers on Linux, the first step is the requirement to fix suspend/resume, and allow modesetting on multiple crtc/output combinations, the other goals are not directly within the scope of this work, you can take steps to do get where we want, but we don't need to move all drivers at once to get there... we also can't just merge something like that to the kernel...

Quoted 9 lines
Quoted 6 lines

Your old ideas were mostly limited by the fact that you didn't get the crtc/output distinction and persisted with the idea of heads which put policy in the kernel, this was a major failing you never discovered, and I didn't probably look enough at the time, since then Keith Packard has done a lot of work on randr 1.2 to show the path to what we actually wanted.

I thought Luc Verhaegen figured that out not Keith.

Luc figured it out then, Keith made it work for things that aren't unichrome and spent the time getting the interfaces into the X server..

Quoted 6 lines

Call it whatever you want and I have wasted far too much time arguing with you and Keith and I can never get agreement on anything. BTW, should I search the LKML archives and find the messages where you call me stupid and block my patches merging fbdev/DRM? That's effectively what you are doing right now.

Yup please do, we are doing something seriously different to what you were trying to do at the time, as we have the experience of the randr work which demonstrated a path forward rather than trying to strive for the end...

Quoted 11 lines

There is a significant group of Linux users who want to be able to login separate users to each screen/head/crtc/output device. These people are concentrated in the third world and don't show up at OLS to argue their case.

There is another group that wants Unicode consoles. The people I talked to were from India and Japan.

I am not a member of either group. So go ahead and ignore me, I'd just like to see these two groups get features implemented that have been ignored for a long time.

These people are free to implement these features, we are doing nothing to block any of these things from happening, but we are not going to write a userspace console until such time as having a userspace console becomes useful, whereas we are enabling someone else to write one on top of the drm now....

We are not going to write a multi-head setup for someone but we are enabling the setting up of one using the graphics drivers that support it, we aren't going to enable every driver at once but allow others to move things over as they like,

The reason this stuff is mainly ending up in the drm is separating the modesetting from the memory management is definitely not a good plan and drm has the memory management code now...

We also have VGA arbitration to worry about but again this is "orthogonal" to the problem space we are currently trying to fix which is just that we need to suspend/resume GPUs properly and set modes on multiple output/crtc combos from the kernel.

Dave.

#40 lore raw
In reply to Jon Smirl
Quoted 7 lines · Jon Smirl

There is a significant group of Linux users who want to be able to login separate users to each screen/head/crtc/output device. These people are concentrated in the third world and don't show up at OLS to argue their case.

There is another group that wants Unicode consoles. The people I talked to were from India and Japan.

If these "significant groups" do not bubble up to the surface, nothing we can do about that.

Jeff

#41 lore raw
Quoted 11 lines · Jeff Garzik
Quoted 7 lines · Jon Smirl

There is a significant group of Linux users who want to be able to login separate users to each screen/head/crtc/output device. These people are concentrated in the third world and don't show up at OLS to argue their case.

There is another group that wants Unicode consoles. The people I talked to were from India and Japan.

If these "significant groups" do not bubble up to the surface, nothing we can do about that.

You need to take into account that these features have been asked about for years and we didn't respond. People interested in this have turned to other solutions.

James Simmons maintained a multi-seat version of the 2.4 kernel for years that had many happy users. I don't know the details about why it never got merged. I believe two companies built special multi-head video hardware for it (Appian and Matrox? it has been a while).

People needing Unicode console support can't speak English. How can they complain on LKML? Linux is an OS for the world, we really should make Unicode console work.

Signature · 2 lines
Jon Smirl
[email protected]
#42 lore raw
In reply to Jon Smirl
Quoted 7 lines · Jon Smirl

When I went through the design process for all this I came to the same conclusion about needing a user space console process.

User space console does impact on all of this because it implies that the current console should be be defeatured down until it becomes only a system recovery console and not a console for everyday use.

I do agree (heh, for once) with that in the sense that in the long run, we should strip the kernel console down to the bare minimum to boot, display oopses, etc... and have all the fancy stuff, unicode, VT, and more in a userspace console process.

However, I'm a little bit worried that we'll end up with 10 competing incompatible and inconsistent userspace console projects and -that- will be horrible.

But it's something separate from what Dave and Jesse are trying to address. Let's first gets the fundation right and -then- we can do all sort of crazy things. Or maybe you can start working on a user console project in parallel using the new APIs that Jesse and Dave are providing ? :-)

Quoted 7 lines

For example, one part of the defeaturing would be to remove the drawing acceleration code in the existing fbdev console drivers and to rework it to support accelerated drawing from the user space console implementation. You want the system recovery console mode to be as simple as possible so that it is always guaranteed to work. User space console is also what leads to the idea of compiling VT out of the kernel.

I do agree on that in the long run, but again, let's look into this -after- we have solved the more immediate issues. We can probably kill most of fbdev, fbcon and current VT once we have a solid userland based replacement that isn't completely bloated (maybe with a "slim" version that does only VGA and non-utf8 for server type apps).

Quoted 3 lines

Once you decide that a user space console is needed then the per CRTC device node becomes more obvious since different people can be logged onto the different consoles.

That's irrelevant. Implementation detail.

Quoted 2 lines

All of the points in the list are interrelated and the architecture needs to address everything as a unified whole.

And that's bullshit :-)

Ben.

#43 lore raw
In reply to Dave Airlie
Quoted 6 lines · Dave Airlie
Quoted 2 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

Stupid idea, we need something to control policy, this isn't going in the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

"I need root to do graphics" is a myopic, antiquated view of the world.

Jeff

#44 lore raw
Quoted 9 lines
Quoted 2 lines

the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

"I need root to do graphics" is a myopic, antiquated view of the world.

X server: priviledges below everything, pageable
kernel: priviledges as high as conceivable, non-pageable

So why do you want it in kernel.... security is not the sensible answer here.

#45 lore raw
Quoted 6 lines · Alan Cox
Quoted 6 lines
Quoted 2 lines

the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

Quoted 7 lines
Quoted 1 line

"I need root to do graphics" is a myopic, antiquated view of the world.

X server: priviledges below everything, pageable
kernel: priviledges as high as conceivable, non-pageable

So why do you want it in kernel.... security is not the sensible answer here.

Replying/quoting mixup. I was responding to the root-privs userspace aspect, not the "put it in the kernel" aspect.

I do not want it in the kernel (should have snipped that last quoted line).

Jeff

#46 lore raw
In reply to Alan Cox
Quoted 8 lines · Alan Cox
Quoted 8 lines
Quoted 2 lines

the kernel, it can be a lot smaller than X and auditable.. sticking the DRI protocol in the kernel is just pointless..

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

Quoted 7 lines
Quoted 1 line

"I need root to do graphics" is a myopic, antiquated view of the world.

X server: priviledges below everything, pageable
kernel: priviledges as high as conceivable, non-pageable

So why do you want it in kernel.... security is not the sensible answer here.

Have you inspected the multi-megabyte X server for security holes to the same level the kernel has been inspected?

The only part that needs to be in the kernel driver is the code controlling locking and code that plays with the hardware. Moving it into the driver ensures that only the minimal amount of root priv code possible is going to end up in the system. If someone tries to move too much into the kernel I'm sure you'll let them know that it's a bad idea.

The problem right now is that code that needs root priv is all intertwined with code that doesn't need it and it all ends up getting run as root.

BTW, when I prototyped this a couple of years ago by merging Radeon DRM/fbdev I only needed to add about 10K more code to the device driver. Most of that was associated with getting the VBIOS to run in x86 mode when the driver was first loaded. That code can be marked _init. We're not talking about a lot of code needing to go into the kernel.

Signature · 2 lines
Jon Smirl
[email protected]
#47 lore raw
Quoted 2 lines
Quoted 2 lines

So why do you want it in kernel.... security is not the sensible answer here.

I'm not proposing the KGI solution where every device driver presents the same API. That model does require a lot of code in the kernel.

The existing DRM model where each driver provides it's own API is a good one. The user space DRI driver then takes this API and turns it into a standard one. Applying the DRM style model to fbdev may allow parts of fbdev to be moved out to user space.

What I don't want is a permanent root priv process hanging around in the system. It simply isn't needed and I have prototyped a system that runs without root so I know it can be done. With minor mods DRI can run without the need for root, with more major mods the X server can run without the need for root. Most of the mods to the X server are to remove things like PCI bus probing, mode setting and VBIOS support.

Signature · 2 lines
Jon Smirl
[email protected]
#48 lore raw
Quoted 7 lines

What I don't want is a permanent root priv process hanging around in the system. It simply isn't needed and I have prototyped a system that runs without root so I know it can be done. With minor mods DRI can run without the need for root, with more major mods the X server can run without the need for root. Most of the mods to the X server are to remove things like PCI bus probing, mode setting and VBIOS support.

But you always lacked a transition plan and never showed a decent API if memory serves, your methods disregarded back compat usually.
also there is no need to port all drivers there never has been we need to just add config options and work with distros to upgrade to the newer bits..

As Jesse said this is an RFC we are not merging it in the morning however all your comments are hand waving so far we need technical problems with this API.

Dave.

#49 lore raw
In reply to Jeff Garzik
Quoted 6 lines

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

"I need root to do graphics" is a myopic, antiquated view of the world.

Did I say the X server? There are policy decisions that are root only also authorisation of processes to render etc..

I'm not sure we can punt all that in-kernel.

Dave.

Quoted 4 lines

Jeff

#50 lore raw
Quoted 9 lines · Dave Airlie
Quoted 6 lines

It is a quite sensible idea.

The userspace X server SHOULD be running under a non-root user, with appropriate fine-grained privs granted to it.

"I need root to do graphics" is a myopic, antiquated view of the world.

Did I say the X server? There are policy decisions that are root only also authorisation of processes to render etc..

Root only today, maybe, but this thread is talking about future directions. Don't lock your design into a coarse-grained security model.

Quoted 1 line

I'm not sure we can punt all that in-kernel.

See my response to Alan.

Jeff

#51 lore raw
Quoted 6 lines
Quoted 2 lines

Did I say the X server? There are policy decisions that are root only also authorisation of processes to render etc..

Root only today, maybe, but this thread is talking about future directions. Don't lock your design into a coarse-grained security model.

We can add a new capability bit but there are certain operations that need privs especially if multiple users are involved. binding outputs to crtcs being one.

Again I can see little reason that this wouldn't be possible going forward. But i'm seeing policy decisions we currently make in the X server needing to be made somewhere.

Dave.

Quoted 10 lines
Quoted 2 lines

I'm not sure we can punt all that in-kernel.

See my response to Alan.

Jeff

#53 lore raw
Quoted 3 lines · On Tue, 22 May 2007 12:06:11 -0400 "Jon Smirl" <[email protected]> wrote:

Someone just pinged me privately asking about virtualization support for the console and graphics hardware. What's the plan for handling virtualization?

qemu already emulates a fairly crappy PCI video card. Since X supports remote display properly thats sufficient for most things.

Alan

#54 lore raw
In reply to Jon Smirl
Quoted 3 lines · Jon Smirl

Someone just pinged me privately asking about virtualization support for the console and graphics hardware. What's the plan for handling virtualization?

Step one: avoid VBIOS, and drive the hardware with open source software we have written :)

Jeff

#55 lore raw
In reply to Dave Airlie
Quoted 9 lines · Dave Airlie
Quoted 2 lines

6) Eliminate the existing VT swap driver free for all. I would

compile

Quoted 2 lines

out the VT layer and replace it with a compatible API that enforces some sanity.

I'm hoping to look into this but it is a parallel problem to what this code does, the VT switch API sucks rocks, so providing something compatible is going to suck rocks..

Yeah, please, don't even go near that until everything else is done & merged or you'll never have anything finished :-) VT is a can of worms that will take some time to sort out and has nothing to do with what we are talking about right now anyway :-)

Ben.

#56 lore raw
In reply to Jon Smirl
Quoted 17 lines · Jon Smirl
Quoted 16 lines · Jesse Barnes
Quoted 14 lines · Jesse Barnes
Quoted 5 lines

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

Maybe you should take a look at the patches. :) The code I posted actually creates an fb device as a slave of the DRM device, and uses that for the boot console. Once you've booted, you can use the new interfaces to do whatever you want with the graphics device... though it doesn't create /dev/fb* devices per-CRTC like you seem to want, it's really easy to do the equivalent with a small userspace program (though I haven't actually tested sharing of buffer objects, it should work).

Quoted 7 lines
Quoted 4 lines

Actually, scratch that last bit. I forgot about a recent change alanh committed that did just that: per-CRTC FB devices. So please take a close look (modesetting-101 of mesa/drm git at freedesktop.org) and let me know if you see any gaping holes.

Here are some of the goals that I believe a rewrite of the graphics system should address:

I think we're talking past each other. I addressed many of the points below in my initial post...

Quoted 3 lines

1) Be upwards compatible with the existing fbdev drivers. This lets us avoid rewriting the 90 existing drivers. New drivers shouldn't break any old apps.

That's there, see the patches.

Quoted 2 lines

2) Address the long outstanding issue of multi-seat at the console level. My solution to this is the one device per CRTC model.

Also covered.

Quoted 2 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

This is an implementation detail. I can understand not wanting to run a huge X server for this purpose, but I've already said that it can be done with far less code for environments with different needs.

Quoted 1 line

4) OOPS should always display even if in a graphics mode

This is definitely a goal, and something I spelled out in my initial post. I think we'll need a new KD_* type to cover this case (i.e. not KD_TEXT but not quite KD_GRAPHICS either). This should be fairly straightforward once I have some good user level apps running on top of these interfaces.

Quoted 1 line

5) Support Secure Attention Key (SAK).

This is more of a console issue, not really a graphics design issue I think.

Quoted 3 lines

6) Eliminate the existing VT swap driver free for all. I would compile out the VT layer and replace it with a compatible API that enforces some sanity.

Again, called out in my initial post. Yes, the kernel should save/restore state by itself and not rely on some userspace application. However, we don't want to break the VT switch API either, so we'll still likely need a heavyweight save/restore state mechanism somewhere.

Quoted 1 line

7) Support Unicode on the console

A userspace console using these interfaces could do this, it's not really a kernel graphics problem.

Quoted 6 lines

8) Allow multiple user space graphics systems to run. These user space systems should not touch the hardware, instead they ask the kernel driver to manipulate the hardware on their behalf. Of course the kernel driver is only the minimum code needed to arbitrate control of the resources - it doesn't do things like implement drawing algorithms.

This is already done.

Quoted 1 line

9) Booting on non-VGA hardware still needs to work.

I don't see what this has to do with the overall design, it's a driver problem (well aside from polluting the generic interfaces with VGA knowledge, which I'm not planning on doing).

Quoted 1 line

10) Support things like cloning and output device selection.

Already done.

Again, *please* take a look at the description in my initial post and the patches themselves (or the modesetting-101 branch in the drm tree). I think that'll lead to a more concrete discussion about what's missing/needed, etc.

Thanks,
Jesse

#57 lore raw
In reply to Jon Smirl
Quoted 2 lines · Jon Smirl

2) Address the long outstanding issue of multi-seat at the console level. My solution to this is the one device per CRTC model.

This is very very low priority. Pretty much nobody besides you is clamoring for it.

Quoted 2 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

Agreed.

Quoted 1 line

4) OOPS should always display even if in a graphics mode

Agreed, and this was in the list that Jesse(?) posted.

Quoted 1 line

8) Allow multiple user space graphics systems to run. These user space

Another very very low priority item.

There are a lot more important things to work on. Linux is about what people need -right now-, not what you think Linux might need in the future; not what you think might be nice to have.

Jeff

#58 lore raw
Quoted 19 lines · Jeff Garzik
Quoted 2 lines · Jon Smirl

2) Address the long outstanding issue of multi-seat at the console level. My solution to this is the one device per CRTC model.

This is very very low priority. Pretty much nobody besides you is clamoring for it.

Quoted 2 lines

3) Eliminate the need for a root priv controlling process. Get rid of the potential for a security hole.

Agreed.

Quoted 1 line

4) OOPS should always display even if in a graphics mode

Agreed, and this was in the list that Jesse(?) posted.

Quoted 7 lines
Quoted 1 line

8) Allow multiple user space graphics systems to run. These user space

Another very very low priority item.

There are a lot more important things to work on. Linux is about what people need -right now-, not what you think Linux might need in the future; not what you think might be nice to have.

I am not asking that these features be implemented today. I am asking that enough planning go into the architecture today to make sure that these features can be built in the future without tearing up the graphics system for a third time.

This is the essence of my complaint about this patch. The patch introduces a new low level graphics API to the kernel. Once we put an API in it is basically impossible to get it back out. I am not convinced that enough planning has gone into this API yet.

I'm also not convinced that there is a transition plan in place to ensure that all drivers get updated to this new API. The last thing we want is to maintain two parallel sets of video drivers forever into the future. V4L2 did something similar to this and orphaned a lot of drivers that the distributions were forced into updating later.

Mode setting is intimately intertwined with the console. VT swapping adds another messy layer which can and should be eliminated in a redesign. Multi-seat and unicode add more complexity. All of this needs to be designed as a unified system. Satisfying the needs of the X server is the easiest piece of the puzzle.

Signature · 2 lines
Jon Smirl
[email protected]
#59 lore raw
Quoted 9 lines · Jon Smirl

I am not asking that these features be implemented today. I am asking that enough planning go into the architecture today to make sure that these features can be built in the future without tearing up the graphics system for a third time.

This is the essence of my complaint about this patch. The patch introduces a new low level graphics API to the kernel. Once we put an API in it is basically impossible to get it back out. I am not convinced that enough planning has gone into this API yet.

Jon, that's why I'm posting this stuff in the first place! :) Again, if you have specific problems with the proposed interfaces (problems that would preclude your wishlist from being fully implementable), please let me know (preferably with specifics).

Thanks,
Jesse

#60 lore raw
Quoted 4 lines · Jesse Barnes

Jon, that's why I'm posting this stuff in the first place! :) Again, if you have specific problems with the proposed interfaces (problems that would preclude your wishlist from being fully implementable), please let me know (preferably with specifics).

A simple place to start is OOPS display while in graphics mode. If we going to tear up the kernel graphics system this is something that needs to be fixed.

I don't think it is safe for the OOPS code to attempt a mode change to text mode when the OOPS happens. The OOPS could have happened in a 3D driver and left the GPU messed up. The safest thing to do is to display the OOPS using the mode that is already set.

This implies that the kernel driver needs to track the dimensions and location of the framebuffer and whether it is in text/graphics mode (this hasn't been possible before because X never tells the kernel what mode it is setting). You also need to bring in the bitmap copy code and fonts over from fbdev. When the OOPS happens you use this info to paint the OOPS onto the screen. The code from fbdev will let you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be achieved by using call_usermode helper to trigger an external app. You also need to get the x86 emulator working so that this will work on non-x86 platforms (benh has already done this). I've aput the hooks into place to give you access to the VBIOS from sysfs. This app is a prime candidate for klibc. This app is strongly coupled to the problem of VGA arbitration.

Could we try and work out a solution to these two problems? If we can solve these they will provide a foundation for fixing the harder ones.

Signature · 2 lines
Jon Smirl
[email protected]
#61 lore raw
Quoted 15 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

Jon, that's why I'm posting this stuff in the first place! :) Again, if you have specific problems with the proposed interfaces (problems that would preclude your wishlist from being fully implementable), please let me know (preferably with specifics).

A simple place to start is OOPS display while in graphics mode. If we going to tear up the kernel graphics system this is something that needs to be fixed.

I don't think it is safe for the OOPS code to attempt a mode change to text mode when the OOPS happens. The OOPS could have happened in a 3D driver and left the GPU messed up. The safest thing to do is to display the OOPS using the mode that is already set.

Quoted 9 lines

This implies that the kernel driver needs to track the dimensions and location of the framebuffer and whether it is in text/graphics mode (this hasn't been possible before because X never tells the kernel what mode it is setting). You also need to bring in the bitmap copy code and fonts over from fbdev. When the OOPS happens you use this info to paint the OOPS onto the screen. The code from fbdev will let you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

What does this have to do with Jesse's patches? this is a totally orthogonal issue..

We will fix this once we have the basic modesetting code working,

Quoted 9 lines

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be achieved by using call_usermode helper to trigger an external app. You also need to get the x86 emulator working so that this will work on non-x86 platforms (benh has already done this). I've aput the hooks into place to give you access to the VBIOS from sysfs. This app is a prime candidate for klibc. This app is strongly coupled to the problem of VGA arbitration.

Again orthogonal problem, VGA arbitration isn't going to matter for this stuff, and we can have initramfs sw do vbetool post on non-initialised cards at startup even now (it may not always work as some cards may not have BIOSes in the right place s and we need the VGA arb to work to do it properly...)

These are nothing to do with the work we are doing, and I think a big part of your problem with working on this previously is you have linked together a group of orthogonal problems into one big problem, when really there are 5-10 problems all of which can be solved separately...

Dave.

#62 lore raw
Quoted 26 lines · Dave Airlie
Quoted 15 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

Jon, that's why I'm posting this stuff in the first place! :) Again, if you have specific problems with the proposed interfaces (problems that would preclude your wishlist from being fully implementable), please let me know (preferably with specifics).

A simple place to start is OOPS display while in graphics mode. If we going to tear up the kernel graphics system this is something that needs to be fixed.

I don't think it is safe for the OOPS code to attempt a mode change to text mode when the OOPS happens. The OOPS could have happened in a 3D driver and left the GPU messed up. The safest thing to do is to display the OOPS using the mode that is already set.

Quoted 9 lines

This implies that the kernel driver needs to track the dimensions and location of the framebuffer and whether it is in text/graphics mode (this hasn't been possible before because X never tells the kernel what mode it is setting). You also need to bring in the bitmap copy code and fonts over from fbdev. When the OOPS happens you use this info to paint the OOPS onto the screen. The code from fbdev will let you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

Quoted 4 lines

What does this have to do with Jesse's patches? this is a totally orthogonal issue..

We will fix this once we have the basic modesetting code working,

These are not isolated problems. Linux needs a properly designed graphics subsystem. One way to achieve that is to design it all on paper first so that we can try and locate the interactions between modules. For example the current mode setting design is definitely broken for multi-seat support, that's because you didn't take that feature into account when writing the code.

Putting a small module into the kernel first with a random API, then try and build the next module is not a good development path. It is better to design all of the modules on paper and then work backwards to the API the first module needs. Even better would be to get the whole subsystem working before including it in the kernel. Once these exposed APIs go it, it is impossible to get them out. We need to try and make sure that they are correct to begin with.

You need to take into account that you are proposing the replacement of an existing subsystem, not the initial inclusion of a virgin system. Putting your code in as is does make the X server happy, but it is not solving all of the known problems with the existing graphics subsystem. If you just want to make to X server happy it would be better to extend the existing fbdev API and not try and replace the subsystem.

Signature · 2 lines
Jon Smirl
[email protected]
#63 lore raw
Quoted 6 lines

These are not isolated problems. Linux needs a properly designed graphics subsystem. One way to achieve that is to design it all on paper first so that we can try and locate the interactions between modules. For example the current mode setting design is definitely broken for multi-seat support, that's because you didn't take that feature into account when writing the code.

No it isn't the code Jesse posted can handle multi-seat fine in the areas that it makes sense as we've pointed out to you you cannot just divide a GPU up into two head and not have the users interfere with each other, reprogramming modes on multiple crtcs/outputs and setting up memory bandwidth calculations requires the driver to do things that will potentially disrupt the other user, in most cases setting a mode on a head requires turning off all devices on the card first and switching them back on in a certain order, this is usually due to clocking interactions,

We can provide two fb interfaces for users wanting to do what you want, we then need to fix the VT subsystem on top of that, however for most of our users (like 95% at least) we want to support X as best we can, and that is where the energy will be placed initially, reducing the number of mode changes on startup along with suspend/resume for users is a major goal of this work.

Quoted 7 lines

Putting a small module into the kernel first with a random API, then try and build the next module is not a good development path. It is better to design all of the modules on paper and then work backwards to the API the first module needs. Even better would be to get the whole subsystem working before including it in the kernel. Once these exposed APIs go it, it is impossible to get them out. We need to try and make sure that they are correct to begin with.

Fine, but nobody has succeded at this, because the effort of doing it this way is not incrementally developed, we are not designing DX10, we are improving Linux graphics one step at a time.

Quoted 8 lines

You need to take into account that you are proposing the replacement of an existing subsystem, not the initial inclusion of a virgin system. Putting your code in as is does make the X server happy, but it is not solving all of the known problems with the existing graphics subsystem. If you just want to make to X server happy it would be better to extend the existing fbdev API and not try and replace the subsystem.

The thing is we need integration with memory management, the memory management is in the drm as it is complicated and the work is done, I know you aren't even reading this sentence at this point.

Dave.

#64 lore raw
Quoted 9 lines · Dave Airlie
Quoted 6 lines

These are not isolated problems. Linux needs a properly designed graphics subsystem. One way to achieve that is to design it all on paper first so that we can try and locate the interactions between modules. For example the current mode setting design is definitely broken for multi-seat support, that's because you didn't take that feature into account when writing the code.

No it isn't the code Jesse posted can handle multi-seat fine in the areas that it makes sense as we've pointed out to you you cannot just

The code doesn't create one device per CRTC. Missing that feature means that we need a persistent root priv app around that owns the single device and then listens for messages from each seat asking it to do things. That root priv app is not necessary, it is a security risk and it should be eliminated.

Quoted 7 lines

divide a GPU up into two head and not have the users interfere with each other, reprogramming modes on multiple crtcs/outputs and setting up memory bandwidth calculations requires the driver to do things that will potentially disrupt the other user, in most cases setting a mode on a head requires turning off all devices on the card first and switching them back on in a certain order, this is usually due to clocking interactions,

All this doesn't mean that it is impossible. I'm not asking you to write this today, I just want an API that will allow it in the future. The last graphics API was with us 25 years, I would hope that the replacement can make it at least six months without needing changes. I believe this feature will be much easier to implement on DX10 hardware which will be wide spread in a few years.

Quoted 6 lines

We can provide two fb interfaces for users wanting to do what you want, we then need to fix the VT subsystem on top of that, however for most of our users (like 95% at least) we want to support X as best we can, and that is where the energy will be placed initially, reducing the number of mode changes on startup along with suspend/resume for users is a major goal of this work.

Everyone runs X because we have built an environment where it is pretty much impossible to create an alternative graphics system. If the low level graphics system is going to get rewritten it is a crime to do it to only serve the needs of X. Linux is about choice; it's time we fixed the low level graphics system to make choice possible. If you haven't noticed the other two major OSes have switched to graphics systems based on 3D hardware. It is pretty much impossible to build a graphics system like that for Linux given the current state of low level graphics support.

Quoted 11 lines
Quoted 7 lines

Putting a small module into the kernel first with a random API, then try and build the next module is not a good development path. It is better to design all of the modules on paper and then work backwards to the API the first module needs. Even better would be to get the whole subsystem working before including it in the kernel. Once these exposed APIs go it, it is impossible to get them out. We need to try and make sure that they are correct to begin with.

Fine, but nobody has succeeded at this, because the effort of doing it this way is not incrementally developed, we are not designing DX10, we are improving Linux graphics one step at a time.

And the right way to build a house is to build the kitchen first and figure out the rest after the kitchen is finished.

Quoted 11 lines
Quoted 7 lines

You need to take into account that you are proposing the replacement of an existing subsystem, not the initial inclusion of a virgin system. Putting your code in as is does make the X server happy, but it is not solving all of the known problems with the existing graphics subsystem. If you just want to make to X server happy it would be better to extend the existing fbdev API and not try and replace the subsystem.

The thing is we need integration with memory management, the memory management is in the drm as it is complicated and the work is done, I know you aren't even reading this sentence at this point.

A new memory manager for drm is a nice piece of work. It was something that needed to get done. But right now it is being done in an X specific manner without consideration of alternative graphics environments.

Quoted 3 lines

Dave.

Signature · 2 lines
Jon Smirl
[email protected]
#65 lore raw

Hi!

Quoted 17 lines
Quoted 8 lines
Quoted 1 line

These are not isolated problems. Linux needs a

properly designed

Quoted 1 line

graphics subsystem. One way to achieve that is to

design it all on

Quoted 1 line

paper first so that we can try and locate the

interactions between

Quoted 1 line

modules. For example the current mode setting design

is definitely

Quoted 8 lines
Quoted 1 line

broken for multi-seat support, that's because you

didn't take that

Quoted 1 line

feature into account when writing the code.

No it isn't the code Jesse posted can handle multi-seat fine in the
areas that it makes sense as we've pointed out to you you cannot just

Quoted 9 lines

The code doesn't create one device per CRTC. Missing that feature
means that we need a persistent root priv app around that owns the
single device and then listens for messages from each seat asking it
to do things. That root priv app is not necessary, it is a security
risk and it should be eliminated.

Fine, submit a patch. But don't block other people patches just because they do not address your favourite problem.

Quoted 9 lines
Quoted 5 lines

Fine, but nobody has succeeded at this, because the effort of doing it
this way is not incrementally developed, we are not designing DX10, we
are improving Linux graphics one step at a time.

And the right way to build a house is to build the kitchen first and
figure out the rest after the kitchen is finished.

...and the right way to build a house is to do nothing, and chase away anyone trying to do something?

Quoted 7 lines
Quoted 6 lines

The thing is we need integration with memory management, the memory
management is in the drm as it is complicated and the work is done, I
know you aren't even reading this sentence at this point.

Quoted 7 lines

A new memory manager for drm is a nice piece of work. It was something
that needed to get done. But right now it is being done in an X
specific manner without consideration of alternative graphics
environments.

Feel free to post alternative patch that addresses that...

Fact is, everyone runs X these days. 'Your patches can't go in, because you do not support alternative graphics systems (that don't exist)' is pretty weak argument.

Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#66 lore raw
Quoted 29 lines · Pavel Machek

Hi!

Quoted 17 lines
Quoted 8 lines
Quoted 1 line

These are not isolated problems. Linux needs a

properly designed

Quoted 1 line

graphics subsystem. One way to achieve that is to

design it all on

Quoted 1 line

paper first so that we can try and locate the

interactions between

Quoted 1 line

modules. For example the current mode setting design

is definitely

Quoted 8 lines
Quoted 1 line

broken for multi-seat support, that's because you

didn't take that

Quoted 1 line

feature into account when writing the code.

No it isn't the code Jesse posted can handle multi-seat fine in the
areas that it makes sense as we've pointed out to you you cannot just

Quoted 9 lines

The code doesn't create one device per CRTC. Missing that feature
means that we need a persistent root priv app around that owns the
single device and then listens for messages from each seat asking it
to do things. That root priv app is not necessary, it is a security
risk and it should be eliminated.

Quoted 2 lines

Fine, submit a patch. But don't block other people patches just because they do not address your favourite problem.

I have already implemented this once and submitted a patch.

Search in the paper for this paragraph:
http://jonsmirl.googlepages.com/graphics.html
DRM also implements the concept of a master user with more capabilities than normal users. These extra capabilities allow the graphics device to be initialized and the consumption of GPU resources to be controlled. The current X server, which runs as root, functions as the DRM master. There is actually no real requirement that the DRM master be run as root, and there is a preliminary patch that removes this requirement.

That paragraphs contains a link to the code that used to be hosted at freedesktop.org. Maybe they can still find it.

Signature · 2 lines
Jon Smirl
[email protected]
#67 lore raw

Hi!

Quoted 30 lines
Quoted 30 lines
Quoted 7 lines
Quoted 7 lines
Quoted 1 line

These are not isolated problems. Linux needs a

properly designed

Quoted 1 line

graphics subsystem. One way to achieve that is to

design it all on

Quoted 1 line

paper first so that we can try and locate the

interactions between

Quoted 1 line

modules. For example the current mode setting

design

Quoted 6 lines
Quoted 6 lines

is definitely

Quoted 1 line

broken for multi-seat support, that's because you

didn't take that

Quoted 1 line

feature into account when writing the code.

No it isn't the code Jesse posted can handle

multi-seat

Quoted 11 lines
Quoted 3 lines

fine in the
areas that it makes sense as we've pointed out to you you cannot just

The code doesn't create one device per CRTC. Missing that feature
means that we need a persistent root priv app around that owns the
single device and then listens for messages from each seat asking it
to do things. That root priv app is not necessary, it

is

Quoted 2 lines

a security
risk and it should be eliminated.

Quoted 6 lines
Quoted 3 lines

Fine, submit a patch. But don't block other people patches just
because they do not address your favourite problem.

I have already implemented this once and submitted a patch.

Seems you were not persistent enough. 'I submitted a patch long time ago' is still no reason to block new work.

Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#68 lore raw
Quoted 5 lines · Pavel Machek
Quoted 2 lines

I have already implemented this once and submitted a patch.

Seems you were not persistent enough. 'I submitted a patch long time ago' is still no reason to block new work.

This is a well researched area and the flaws are widely know. Adding this new mode setting code to the kernel is not adding a new subsystem, it is an attempt to replace an existing subsystem. In order to replace a subsystem the general rule is that the new one must be better than the old one. I have not seen sufficient arguments made to justify replacing fbdev instead of extending it.

As for writing more patches, I have been burnt once by "show us the code" being used as a way to getting rid of someone when the people saying "show us the code" have no intention of agreeing to the changes being proposed. I'm not going to fall for it again.

Signature · 2 lines
Jon Smirl
[email protected]
#69 lore raw
In reply to Jon Smirl
Quoted 3 lines

you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

If we know how yes. Probably the X server needs to provide us with a simple list of operations to perform or failing that write 128K of null to the display then print the characters (the 128K should ensure any running FIFO for commands is stuffed and we get back to the framebuffer)

Quoted 2 lines

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be

We don't want to touch the video bios for most cards, its not as good as the X mode switcher code, nor for that matter does it work in a lot of cases as they use IRQ and DMA functions sometimes.

Alan

#70 lore raw
Quoted 9 lines · Alan Cox
Quoted 3 lines

you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

If we know how yes. Probably the X server needs to provide us with a simple list of operations to perform or failing that write 128K of null to the display then print the characters (the 128K should ensure any running FIFO for commands is stuffed and we get back to the framebuffer)

Quoted 6 lines
Quoted 2 lines

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be

We don't want to touch the video bios for most cards, its not as good as the X mode switcher code, nor for that matter does it work in a lot of cases as they use IRQ and DMA functions sometimes.

The only reason the VBIOS is run is to initially reset the card. Once we get the card reset it isn't used any more. For almost all cards this is the only way to reset them, we have insufficient information to write this ourselves.

Quoted 3 lines

Alan

Signature · 2 lines
Jon Smirl
[email protected]
#71 lore raw
Quoted 14 lines · Jon Smirl
Quoted 13 lines · Alan Cox
Quoted 3 lines

you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

If we know how yes. Probably the X server needs to provide us with a simple list of operations to perform or failing that write 128K of null to the display then print the characters (the 128K should ensure any running FIFO for commands is stuffed and we get back to the framebuffer)

Quoted 2 lines

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be

Quoted 8 lines
Quoted 3 lines

We don't want to touch the video bios for most cards, its not as good as the X mode switcher code, nor for that matter does it work in a lot of cases as they use IRQ and DMA functions sometimes.

The only reason the VBIOS is run is to initially reset the card. Once we get the card reset it isn't used any more. For almost all cards this is the only way to reset them, we have insufficient information to write this ourselves.

We should aim to get away from this though. For Intel and VIA chips, we have enough info to do full card setup ourselves. IIRC there's some early code to do the same for ATI chips (not sure about other chips though). If we can avoid using the VBIOS, our drivers will be far more portable and featureful than they'd be otherwise. For example, current ATI drivers simply can't do full multihead on many setups because it relies on the BIOS to setup external DAC chips, and in many cases the BIOS doesn't. In order to address that, we need to learn how to do it ourselves... So if at all possible, I'd like to avoid baking any assumptions about VBIOS POST into this design.

Jesse

#72 lore raw
Quoted 24 lines · Jesse Barnes
Quoted 14 lines · Jon Smirl
Quoted 13 lines · Alan Cox
Quoted 3 lines

you display text in graphics mode entirely in kernel context. The driver should also attempt to stop the GPU to try and make sure it doesn't erase the OOPS display.

If we know how yes. Probably the X server needs to provide us with a simple list of operations to perform or failing that write 128K of null to the display then print the characters (the 128K should ensure any running FIFO for commands is stuffed and we get back to the framebuffer)

Quoted 2 lines

Another simple thing that needs to be built is a mechanism to run the VBIOS in x86 mode when the driver is first loaded. This can be

Quoted 8 lines
Quoted 3 lines

We don't want to touch the video bios for most cards, its not as good as the X mode switcher code, nor for that matter does it work in a lot of cases as they use IRQ and DMA functions sometimes.

The only reason the VBIOS is run is to initially reset the card. Once we get the card reset it isn't used any more. For almost all cards this is the only way to reset them, we have insufficient information to write this ourselves.

Quoted 10 lines

We should aim to get away from this though. For Intel and VIA chips, we have enough info to do full card setup ourselves. IIRC there's some early code to do the same for ATI chips (not sure about other chips though). If we can avoid using the VBIOS, our drivers will be far more portable and featureful than they'd be otherwise. For example, current ATI drivers simply can't do full multihead on many setups because it relies on the BIOS to setup external DAC chips, and in many cases the BIOS doesn't. In order to address that, we need to learn how to do it ourselves... So if at all possible, I'd like to avoid baking any assumptions about VBIOS POST into this design.

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings. They flash the right VBIOS that matches the chip into the ROM on the card. Given all the various steppings this is the only sane way to initialize the hardware. I don't believe generic initialization code that can handle all of the various steppings exists for any hardware.

Signature · 2 lines
Jon Smirl
[email protected]
#73 lore raw
Quoted 2 lines

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings.

ATI won't even tell us how to do 2D mode setting or clear the code under NDA that does so. So we don't support AMD (aka ATI) video hardware anyway. Until they grow up its an irrelevant case.

The problem is how to support the hardware of people who will work sanely with the free software community and how to do it well. If it makes life worse for those who don't then that is their problem.

Alan

#74 lore raw
In reply to Jon Smirl
Quoted 6 lines · Jon Smirl

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings. They flash the right VBIOS that matches the chip into the ROM on the card. Given all the various steppings this is the only sane way to initialize the hardware. I don't believe generic initialization code that can handle all of the various steppings exists for any hardware.

I think you must have misunderstood. Last time I worked on ATI, there was a single ROM image that supported several (maybe even all) of their addin cards. There's nothing magical about them... But that's beside the point.

They may have hardcoded information about how a particular board is wired up--it's ok to use that (makes the DAC discovery much easier). We just want to avoid relying on the VBIOS for DAC setup and output probing, since we'll need to do that ourselves for suspend resume and to fully support various multihead configurations.

Jesse

#75 lore raw
Quoted 8 lines · Jesse Barnes
Quoted 6 lines · Jon Smirl

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings. They flash the right VBIOS that matches the chip into the ROM on the card. Given all the various steppings this is the only sane way to initialize the hardware. I don't believe generic initialization code that can handle all of the various steppings exists for any hardware.

Quoted 4 lines

I think you must have misunderstood. Last time I worked on ATI, there was a single ROM image that supported several (maybe even all) of their addin cards. There's nothing magical about them... But that's beside the point.

What about the poke the obscure value into this undocumented IO port class of problem where they are using the chip test interface to work around bugs in the silicon.

He also mentioned that all of the OEMs change the standard ROM image before loading it onto their cards to handle how they wired things up and bugs in other chips.

Of course I don't have the source for the ROM so I don't know the accuracy of what I was told.

Quoted 9 lines

They may have hardcoded information about how a particular board is wired up--it's ok to use that (makes the DAC discovery much easier). We just want to avoid relying on the VBIOS for DAC setup and output probing, since we'll need to do that ourselves for suspend resume and to fully support various multihead configurations.

Jesse

Signature · 2 lines
Jon Smirl
[email protected]
#76 lore raw
Quoted 18 lines · Jon Smirl
Quoted 8 lines · Jesse Barnes
Quoted 6 lines · Jon Smirl

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings. They flash the right VBIOS that matches the chip into the ROM on the card. Given all the various steppings this is the only sane way to initialize the hardware. I don't believe generic initialization code that can handle all of the various steppings exists for any hardware.

Quoted 4 lines

I think you must have misunderstood. Last time I worked on ATI, there was a single ROM image that supported several (maybe even all) of their addin cards. There's nothing magical about them... But that's beside the point.

What about the poke the obscure value into this undocumented IO port class of problem where they are using the chip test interface to work around bugs in the silicon.

Quoted 6 lines

He also mentioned that all of the OEMs change the standard ROM image before loading it onto their cards to handle how they wired things up and bugs in other chips.

Of course I don't have the source for the ROM so I don't know the accuracy of what I was told.

There is nothing magic about a ROM. It's just software, or, often, data tables.

Jeff

#77 lore raw
In reply to Jon Smirl
Quoted 14 lines · Jon Smirl
Quoted 8 lines · Jesse Barnes
Quoted 6 lines · Jon Smirl

I've talked to an ATI engineer about VBIOS initialization. The chips may have different steppings. They flash the right VBIOS that matches the chip into the ROM on the card. Given all the various steppings this is the only sane way to initialize the hardware. I don't believe generic initialization code that can handle all of the various steppings exists for any hardware.

Quoted 4 lines

I think you must have misunderstood. Last time I worked on ATI, there was a single ROM image that supported several (maybe even all) of their addin cards. There's nothing magical about them... But that's beside the point.

Quoted 7 lines

What about the poke the obscure value into this undocumented IO port class of problem where they are using the chip test interface to work around bugs in the silicon.

He also mentioned that all of the OEMs change the standard ROM image before loading it onto their cards to handle how they wired things up and bugs in other chips.

Right, I think that's where most of the real differences are:
configuration tables. And Linux drivers will want to continue to make use of those.

Quoted 2 lines

Of course I don't have the source for the ROM so I don't know the accuracy of what I was told.

Yeah, it would be nice if we could get the ROM sources, would probably make for some interesting (and maybe frightening) reading. :)

Jesse

#78 lore raw
In reply to Jon Smirl
Quoted 4 lines · Jon Smirl

The only reason the VBIOS is run is to initially reset the card. Once we get the card reset it isn't used any more. For almost all cards this is the only way to reset them, we have insufficient information to write this ourselves.

For suspend/resume to ever work reliably, we need to be able to reinitialise cards without BIOS support. It would be more useful to spend time on that.

Signature · 1 line
Matthew Garrett | [email protected]
#79 lore raw
In reply to Jon Smirl

.

Quoted 10 lines

There is more to fbdev than mode setting. It is also how non-x86 platforms achieve their boot display. How will boot display be handled with the your design? What about console display on non-x86 platforms? Loading both fbdev and the new code puts us right back into the multiple driver fight we have today.

If the kernel graphics system is going to get rewritten the rewrite needs to address all of the existing problems.

We already have fbcon working perfectly on top of this layer... so you might want to actually look at the developed code..

Dave.

#80 lore raw
In reply to Jon Smirl
Quoted 11 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

How is supporting different users logged into each head going to work? The original model for this was to give each head its own fbdev device. It is important that each user be able to set their own mode without being root.

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

As for moving other card drivers they will move as people see fit to move them there probably isn't much gain in moving single crtc/output cards..

Dave.

Quoted 10 lines

Jon Smirl
[email protected]

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

x.org/lkml/

Quoted 1 line

x.org/lkml/

Quoted 1 line
#81 lore raw
Quoted 13 lines · Dave Airlie
Quoted 11 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

How is supporting different users logged into each head going to work? The original model for this was to give each head its own fbdev device. It is important that each user be able to set their own mode without being root.

Quoted 7 lines

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

Solution:
One device per crtc. You can then have two users, running consoles or xservers on their crtcs, without having to involve root.

The crtc->output mapping must still be done by root of course.

This solution allow the useful case where the computer boots, the boot scripts set up a crtc->output mapping. Then users log in through the various consoles (using getty or xdm or similiar) using their grahphical devices in whatever way they want. A true multiseat setup.

And if one user needs to use all the screens for multi-display work? Let root change the mappings, possibly through some sudo setup.

Helge Hafting

#82 lore raw
Quoted 22 lines · Helge Hafting
Quoted 14 lines · Dave Airlie
Quoted 7 lines · Jon Smirl
Quoted 4 lines · Jesse Barnes

In collaboration with the FB guys, we've been working on enhancing the kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several kernel and userspace drivers compete for control of graphics devices.

Quoted 5 lines

How is supporting different users logged into each head going to work? The original model for this was to give each head its own fbdev device. It is important that each user be able to set their own mode without being
root.

Quoted 7 lines

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

Quoted 3 lines

Solution:
One device per crtc. You can then have two users, running consoles or xservers on their crtcs, without having to involve root.

Thats pretty much what the code does, but you still are putting a certain amount of policy in the kernel...

Quoted 10 lines

The crtc->output mapping must still be done by root of course.

This solution allow the useful case where the computer boots, the boot scripts
set up a crtc->output mapping. Then users log in through the various consoles (using getty or xdm or similiar) using their grahphical devices in whatever way they want. A true multiseat setup.

Quoted 3 lines

And if one user needs to use all the screens for multi-display work? Let root change the mappings, possibly through some sudo setup.

Multiseat isn't what i would want as a default on any machine, so the default setup should be to clone the single user onto as many screens as possible, as this is what users expect.. the system startup scripts can then reconfigure it, to suit the admins needs..

Dave.

Quoted 1 line
#83 lore raw
Quoted 29 lines · Dave Airlie
Quoted 28 lines · Helge Hafting
Quoted 4 lines · Dave Airlie
Quoted 3 lines · Jon Smirl
Quoted 1 line · Jesse Barnes

In collaboration with the FB guys, we've been working on

enhancing the

Quoted 1 line
Quoted 1 line
Quoted 1 line

kernel's graphics subsystem in an attempt to bring some sanity

to the

Quoted 1 line
Quoted 1 line
Quoted 1 line

Linux graphics world and avoid the situation we have now where

several

Quoted 1 line
Quoted 1 line
Quoted 1 line

kernel and userspace drivers compete for control of graphics

devices.

Quoted 2 lines
Quoted 2 lines

How is supporting different users logged into each head going to

work?

Quoted 1 line
Quoted 1 line

The original model for this was to give each head its own fbdev

device.

Quoted 11 lines
Quoted 3 lines

It is important that each user be able to set their own mode without being
root.

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

Quoted 6 lines
Quoted 3 lines

Solution:
One device per crtc. You can then have two users, running consoles or xservers on their crtcs, without having to involve root.

Thats pretty much what the code does, but you still are putting a certain amount of policy in the kernel...

What policy would that be?
The mapping is set by root from userspace, not by the kernel. The same for ownership to crtc devices. The kernel may have to provide some default so "init=/bin/sh" will work, that's all.

Quoted 10 lines
Quoted 10 lines

The crtc->output mapping must still be done by root of course.

This solution allow the useful case where the computer boots, the boot scripts
set up a crtc->output mapping. Then users log in through the various consoles (using getty or xdm or similiar) using their grahphical devices in whatever way they want. A true multiseat setup.

Quoted 5 lines
Quoted 3 lines

And if one user needs to use all the screens for multi-display work? Let root change the mappings, possibly through some sudo setup.

Multiseat isn't what i would want as a default on any machine, so the

Sure. Not multiseat by default, as the kernel can't know which output goes with which keyboard. All I want it a system that allows multiseat for those that care to set it up.

Quoted 3 lines

default setup should be to clone the single user onto as many screens as possible, as this is what users expect.. the system startup scripts can then reconfigure it, to suit the admins needs..

Sure. Well, when using multiple screens as a single user, then I don't want cloning. I want a multi-screen desktop. The laptop user with a video projector is about the one case I know where cloning is wanted.

Unfortunately the kernel can't always know which outputs are in use, so I see how cloning may have to be the default. :-/

Helge Hafting

Quoted 8 lines

Dave.

Quoted 1 line

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#84 lore raw
Quoted 11 lines · Helge Hafting
Quoted 11 lines
Quoted 10 lines
Quoted 6 lines

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

Solution:
One device per crtc. You can then have two users, running consoles or xservers on their crtcs, without having to involve root.

Quoted 7 lines
Quoted 2 lines

Thats pretty much what the code does, but you still are putting a certain amount of policy in the kernel...

What policy would that be?
The mapping is set by root from userspace, not by the kernel. The same for ownership to crtc devices. The kernel may have to provide some default so "init=/bin/sh" will work, that's all.

The policy of mapping outputs to CRTCs. Like Dave said, you may have several outputs but only one or two CRTCs, with limitations on how they can be routed. So doing "one device per CRTC" isn't quite enough, you also have to choose an initial output setup. But like you say this could be changed at boot time.

Quoted 3 lines

Sure. Not multiseat by default, as the kernel can't know which output goes with which keyboard. All I want it a system that allows multiseat for those that care to set it up.

Sure, and like I mentioned to Jon in another mail, a decent multiseat setup is possible with these interfaces, albeit with a userlevel graphics daemon to arbitrate what the CRTC->output mappings are and to coordinate access to the hw if needed.

So really, I think the interfaces posted here will do what you want. Maybe you can take a closer look and make sure?

Thanks,
Jesse

#85 lore raw
Quoted 30 lines · Jesse Barnes
Quoted 11 lines · Helge Hafting
Quoted 11 lines
Quoted 10 lines
Quoted 6 lines

TThe problem with that is the concept of heads is flawed... there is in reality no such
thing, you have crtcs and outputs, no heads. So any attempt to enforce the head concept involves putting policy into the kernel, as if I have 3 outputs but 2 crtcs how do I decide the mappings without the admin telling the kernel,

Solution:
One device per crtc. You can then have two users, running consoles or xservers on their crtcs, without having to involve root.

Quoted 7 lines
Quoted 2 lines

Thats pretty much what the code does, but you still are putting a certain amount of policy in the kernel...

What policy would that be?
The mapping is set by root from userspace, not by the kernel. The same for ownership to crtc devices. The kernel may have to provide some default so "init=/bin/sh" will work, that's all.

The policy of mapping outputs to CRTCs. Like Dave said, you may have several outputs but only one or two CRTCs, with limitations on how they can be routed. So doing "one device per CRTC" isn't quite enough, you also have to choose an initial output setup. But like you say this could be changed at boot time.

Quoted 3 lines

Sure. Not multiseat by default, as the kernel can't know which output goes with which keyboard. All I want it a system that allows multiseat for those that care to set it up.

Quoted 7 lines

Sure, and like I mentioned to Jon in another mail, a decent multiseat setup is possible with these interfaces, albeit with a userlevel graphics daemon to arbitrate what the CRTC->output mappings are and to coordinate access to the hw if needed.

So really, I think the interfaces posted here will do what you want. Maybe you can take a closer look and make sure?

What about modifying the existing fbdev API? You could start with one fbdev device per CRTC and then add a new IOCTL to control the output device. I haven't seen anything yet that justifies abandoning the existing fbdev API.

Note that you could add fbdev API support to the radeon DRM driver. Preserving the fbdev API doesn't mean that you have to preserve the old driver code.

Signature · 2 lines
Jon Smirl
[email protected]
#86 lore raw
Quoted 5 lines

What about modifying the existing fbdev API? You could start with one fbdev device per CRTC and then add a new IOCTL to control the output device. I haven't seen anything yet that justifies abandoning the existing fbdev API.

Then you can't aribtrate properly output hooking is a root level thing, you cannot allow the user in multiseat to just pick his own outputs, if you claim to want a truly flexible interfaces, also the crtc->output mappings aren't always simple, there are limitations on most hw about which crtc can map to which output and when you can clone etc.. putting policy for this stuff in-kernel would heavily restrict what the user can do...

At the moment, you can with a small userspace app add two framebuffers, link them to crtcs and link those to outputs, then users can use /dev/fb/* to do what they need, we haven't linked up mode setting so that fbset works yet I don't think, but if people really wanted that we could probably do so... so far we just have enough fbdev to support fbcon...

Dave.

#87 lore raw
Quoted 6 lines · Dave Airlie
Quoted 1 line

What about modifying the existing fbdev API? You could start with

one

Quoted 3 lines

fbdev device per CRTC and then add a new IOCTL to control the output device. I haven't seen anything yet that justifies abandoning the existing fbdev API.

Quoted 7 lines

Then you can't aribtrate properly output hooking is a root level thing, you cannot allow the user in multiseat to just pick his own outputs, if you claim to want a truly flexible interfaces, also the crtc->output mappings aren't always simple, there are limitations on most hw about which crtc can map to which output and when you can clone etc.. putting policy for this stuff in-kernel would heavily restrict what the user can do...

Policy for this kind of thing should just go in HAL's ConsoleKit:
http://lists.freedesktop.org/archives/hal/2007-January/007111.html

Xav

#88 lore raw
In reply to Jesse Barnes
Quoted 7 lines

In collaboration with the FB guys, we've been working on enhancing the
kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several
kernel and userspace drivers compete for control of graphics devices.

.../...

A little note about initial mode setting at boot...

I do stongly beleive that the decision of what mode to choose should not be made in the kernel. At boot the kernel should either leave the HW in whatever state the FW set it (and text mode is fine) or setup some sane default (ie 640x480 has the most chances of working) if that's not an option, maybe some very minimum EDID parsing in case you have a fixed frequency weirdo panel, but that's it (unless it's a mac an OF tells you what to use :-)

The kernel would provide userland with connector infos (presence load detect, EDID, ...) and userland gets to decide what to do.

Some reasons to keep that policy completely out of the kernel even at boot time are:

- User may want to configure his default gfx setup and have it up early

- EDID do lie, monitors routinely ship with windows .inf files
containing "updated" infos apple has that too in OS X (EDID overrides afaik) etc.... and if we're going to do such a database of known monitors, it should definitely not be in the kernel. Besides, we want to add more infos that EDIDs don't provide most of the time to it like subpixel ordering etc...

- It sounds better that way :-) (yeah, that's the best reason !)

So while I agree that the register frobbing, memory management, etc... should be indeed moved to the kernel as you guys have been doing lately, the policy of deciding what mode to set should totally stick to userland.

IMHO, the best would be a lib (or daemon or both) for monitor detection & mode setting that is separate from X :-) That could handle storing the admin's default setup (including weird monitor info if any) and restoring it at boot time, etc...

Cheers,
Ben.

#89 lore raw
Quoted 2 lines · Benjamin Herrenschmidt

I do stongly beleive that the decision of what mode to choose should not be made in the kernel.

That's the plan; the kernel just provides mechanism. The architecture used in the X server splits precisely at this point with the mechanism in the driver and the configuration and policy up in the X server proper. Quite a bit of that code could be broken out into a shared library for fbdev-based apps and the X server to share, but that's down the road a bit after the kernel APIs look a lot more solid.

With the goal of getting to a single-mode-set boot to avoid screen flashing before login, the key here is to make any early user-mode graphics apps share the same kernel graphics infrastructure as the X server to identify the common cases where the startup and X modes are the same and avoid resetting the configuration.

Signature · 1 line
[email protected]
#90 lore raw
Quoted 7 lines · Keith Packard

That's the plan; the kernel just provides mechanism. The architecture used in the X server splits precisely at this point with the mechanism in the driver and the configuration and policy up in the X server proper. Quite a bit of that code could be broken out into a shared library for fbdev-based apps and the X server to share, but that's down the road a bit after the kernel APIs look a lot more solid.

Ok, good plan then.

Quoted 5 lines

With the goal of getting to a single-mode-set boot to avoid screen flashing before login, the key here is to make any early user-mode graphics apps share the same kernel graphics infrastructure as the X server to identify the common cases where the startup and X modes are the same and avoid resetting the configuration.

Ok. Fair enough.

Cheers,
Ben.

#91 lore raw
In reply to Benjamin Herrenschmidt
Quoted 19 lines · Benjamin Herrenschmidt
Quoted 6 lines

In collaboration with the FB guys, we've been working on enhancing the
kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several
kernel and userspace drivers compete for control of graphics devices.

.../...

A little note about initial mode setting at boot...

I do stongly beleive that the decision of what mode to choose should not be made in the kernel. At boot the kernel should either leave the HW in whatever state the FW set it (and text mode is fine) or setup some sane default (ie 640x480 has the most chances of working) if that's not an option, maybe some very minimum EDID parsing in case you have a fixed frequency weirdo panel, but that's it (unless it's a mac an OF tells you what to use :-)

Quoted 2 lines

The kernel would provide userland with connector infos (presence load detect, EDID, ...) and userland gets to decide what to do.

The current code does its best to figure out what modes are available and tries to pick a good one for each display. It sounds like you're mainly concerned with the actual mode picking, not the mode and output detection and enumeration? If so, that's a pretty easy change to make. But if you're also worried about the kernel building mode lists, then we'll have bigger changes to make...

Quoted 19 lines

Some reasons to keep that policy completely out of the kernel even at boot time are:

- User may want to configure his default gfx setup and have it up early

- EDID do lie, monitors routinely ship with windows .inf files
containing "updated" infos apple has that too in OS X (EDID overrides afaik) etc.... and if we're going to do such a database of known monitors, it should definitely not be in the kernel. Besides, we want to add more infos that EDIDs don't provide most of the time to it like subpixel ordering etc...

- It sounds better that way :-) (yeah, that's the best reason !)

So while I agree that the register frobbing, memory management, etc... should be indeed moved to the kernel as you guys have been doing lately, the policy of deciding what mode to set should totally stick to userland.

Quoted 4 lines

IMHO, the best would be a lib (or daemon or both) for monitor detection & mode setting that is separate from X :-) That could handle storing the admin's default setup (including weird monitor info if any) and restoring it at boot time, etc...

I'm not really sure how much of a problem broken EDIDs will be. The X server only has a few quirks for broken EDIDs now, nothing major afaict, and apparently the FB layer already has some code for handling EDID quirks, so I don't think that'll be our biggest problem. So far, it looks like handling laptop panels is a bit trickier (at least for Intel chips)...

Jesse

#92 lore raw
Quoted 7 lines · Jesse Barnes

The current code does its best to figure out what modes are available and tries to pick a good one for each display. It sounds like you're mainly concerned with the actual mode picking, not the mode and output detection and enumeration? If so, that's a pretty easy change to make. But if you're also worried about the kernel building mode lists, then we'll have bigger changes to make...

I'm worried that the EDID we get from the monitor is bogus and needs to be overriden.

Now, if the kernel builds a mode list, that's find if we have a call to "feed" it with a replacement one later on from userland.

In addition, there are all those monitors that cannot be probed (no DDC/EDID) and for which only userland can reasonably provide a mode or a mode list.

So it's a bit of both :-) Building an "initial" mode list from the EDID might be fair enough if we can replace it soon enough, but we still need to be very conservative about whatever boot mode we choose.

Quoted 6 lines

I'm not really sure how much of a problem broken EDIDs will be. The X server only has a few quirks for broken EDIDs now, nothing major afaict, and apparently the FB layer already has some code for handling EDID quirks, so I don't think that'll be our biggest problem. So far, it looks like handling laptop panels is a bit trickier (at least for Intel chips)...

Well, I've seen my share of broken EDID.. Last time I looked at Darwin, I think I saw Apple maintaining a fairly huge database of EDID replacements in userland...

Ben.

#93 lore raw
Quoted 11 lines · Benjamin Herrenschmidt
Quoted 6 lines · Jesse Barnes

The current code does its best to figure out what modes are available and tries to pick a good one for each display. It sounds like you're mainly concerned with the actual mode picking, not the mode and output detection and enumeration? If so, that's a pretty easy change to make. But if you're also worried about the kernel building mode lists, then we'll have bigger changes to make...

I'm worried that the EDID we get from the monitor is bogus and needs to be overriden.

Quoted 6 lines

Now, if the kernel builds a mode list, that's find if we have a call to "feed" it with a replacement one later on from userland.

In addition, there are all those monitors that cannot be probed (no DDC/EDID) and for which only userland can reasonably provide a mode or a mode list.

Yeah, we already have a call to add modes to the kernel's list, so we should be covered.

Quoted 3 lines

So it's a bit of both :-) Building an "initial" mode list from the EDID might be fair enough if we can replace it soon enough, but we still need to be very conservative about whatever boot mode we choose.

Right.

Quoted 10 lines
Quoted 6 lines

I'm not really sure how much of a problem broken EDIDs will be. The X server only has a few quirks for broken EDIDs now, nothing major afaict, and apparently the FB layer already has some code for handling EDID quirks, so I don't think that'll be our biggest problem. So far, it looks like handling laptop panels is a bit trickier (at least for Intel chips)...

Well, I've seen my share of broken EDID.. Last time I looked at Darwin, I think I saw Apple maintaining a fairly huge database of EDID replacements in userland...

Interesting... I wonder how the distro monitor databases compare.

Jesse

#94 lore raw
Quoted 15 lines · Jesse Barnes
Quoted 14 lines · Benjamin Herrenschmidt
Quoted 6 lines · Jesse Barnes

The current code does its best to figure out what modes are available and tries to pick a good one for each display. It sounds like you're mainly concerned with the actual mode picking, not the mode and output detection and enumeration? If so, that's a pretty easy change to make. But if you're also worried about the kernel building mode lists, then we'll have bigger changes to make...

I'm worried that the EDID we get from the monitor is bogus and needs to be overriden.

Now, if the kernel builds a mode list, that's find if we have a call to "feed" it with a replacement one later on from userland.

Quoted 7 lines
Quoted 3 lines

In addition, there are all those monitors that cannot be probed (no DDC/EDID) and for which only userland can reasonably provide a mode or a mode list.

Yeah, we already have a call to add modes to the kernel's list, so we should be covered.

We actually have a function that will replace the entire mode list with a new one safely.

Tony

#95 lore raw
In reply to Benjamin Herrenschmidt
Quoted 8 lines · Benjamin Herrenschmidt
Quoted 2 lines · Jesse Barnes

The current code does its best to figure out what modes are available and tries to pick a good one for each display. It sounds like you're mainly concerned with the actual mode picking, not the mode and output detection and enumeration? If so, that's a pretty easy change to make. But if you're also worried about the kernel building mode lists, then we'll have bigger changes to make...

I'm worried that the EDID we get from the monitor is bogus and needs to be overriden.

How often do that happen?

There is the alternate solution of assuming that EDID is correct, and provide an override when it isn't. So anyone with a good monitor get a nice display by default. Those with a defective lying monitor may have to add a "resolution=640x480" parameter to their kernel command line to get out of the black screen modus. This shifts the bother to those with a bad monitor, who then are free to get pissed off at their monitor vendor . . .

Helge Hafting

#96 lore raw
In reply to Benjamin Herrenschmidt
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 6 lines

In collaboration with the FB guys, we've been working on enhancing the
kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several
kernel and userspace drivers compete for control of graphics devices.

What's the difference between this and Jon Smirls' proposals from early 2005?

Philipp

#97 lore raw
Quoted 10 lines · Philipp Klaus Krause
Quoted 6 lines · Benjamin Herrenschmidt
Quoted 6 lines

In collaboration with the FB guys, we've been working on enhancing the
kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several
kernel and userspace drivers compete for control of graphics devices.

What's the difference between this and Jon Smirls' proposals from early 2005?

There are lots of differences. From memory, Jon tried to enhance the FB layer to do modesetting with an eye toward multiseat support. Modes were set by echoing values into sysfs, and iirc it didn't tie into the DRM layer at all or use proper memory management.

These patches use ioctls on the DRM device for modesetting (at least for now), and provide userspace with maximum flexibility. Framebuffer objects are allocated using the new DRM memory manager, and any FB devices created are slaves of the DRM layer, avoiding some of the fighting over suspend/resume and graphics programming.

Many of the aims are the same though, Jon was trying to address many of the problems outlined in my initial mail too, we just have different opinions about how exactly those problems should be solved. :)

Jesse

#98 lore raw
In reply to Philipp Klaus Krause
Quoted 9 lines · Philipp Klaus Krause
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 6 lines

In collaboration with the FB guys, we've been working on enhancing the
kernel's graphics subsystem in an attempt to bring some sanity to the Linux graphics world and avoid the situation we have now where several
kernel and userspace drivers compete for control of graphics devices.

Quoted 3 lines

What's the difference between this and Jon Smirls' proposals from early 2005?

One of the biggest differences is we have the experience of the randr-1.2 code in the X server and a chipset which is backed my the manufacturer to design and test on. It also makes sure the design is actually real-world useful, I've already deployed this modesetting code in a standalone GL multi-head enviornment using miniglx code.

We also aim to maintain as much compatibility with the current system as possible, whereas Jon really didn't care.

Also Jon proposed about 10 things, but never an actual API, the things he proposed are still problems, but they are I believe as do many others to be orthogonal problems, not the intertwined things that he believes should be lumped under a single API ala DirectX.

Dave.