improve Xfbdev with kernel patch

Under development: PCMCIA, wireless, etc.
Post Reply
Message
Author
User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

improve Xfbdev with kernel patch

#1 Post by technosaurus »

With Xvesa being deprecated (actually completely gone in xorg), the last remaining small Xserver is Xfbdev, but it has one big hurdle.
One of the things that makes Xorg a necessity is all of the manual kernel command line interaction by the user that is needed to set the resolution of the frame buffer. let's see if we can automate that

AFAIK, all of the code is in arch/x86/boot/video.c

Code: Select all

void set_video(void)
{...
	for (;;) {
		if (mode == ASK_VGA)
			mode = mode_menu();
/* TODO:   if (mode == MAX_VGA) mode = mode_max(); */
		if (!set_mode(mode))
			break;
...}
which would need a function:
static unsigned int mode_max(); /* based on mode_menu()*/
here is my best guess:

Code: Select all

static void modemax(void)
{
	struct card_info *card;
	struct mode_info *mi;
	int i;
	int nmodes;
	int visible;
	u16 mode_max;
	u16 res_max = 0;

	nmodes = 0;
	for (card = video_cards; card < video_cards_end; card++)
		nmodes += card->nmodes;

	for (card = video_cards; card < video_cards_end; card++) {
		mi = card->modes;
		for (i = 0; i < card->nmodes; i++, mi++) {
			visible = mi->x && mi->y;
			if (!visible)
				continue; /* Hidden mode */
			if (!mi->depth)
				continue; /* I _think_ we need depth */
			if ((mi->x * mi->y * mi->depth) > res_max){
				res_max=(mi->x * mi->y * mi->depth);
				mode_max = mi->mode ? mi->mode : (mi->y << 8)+mi->x;
			}
		}
	}
return (mode_max)
}
assuming we can get the above to work, we'd need to wedge in a vga=max parameter (but for testing we can just use the vga=ask code by replacing mode_menu with the modemax code)
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#2 Post by technosaurus »

ok, here is the quick hack that I am going to _try_ to build and test it by using vga=ask

Code: Select all

static unsigned int mode_menu(void)
{
	struct card_info *card;
	struct mode_info *mi;
	int i;
	int visible;
	u16 mode_max;
	u16 res_max = 0;

	for (card = video_cards; card < video_cards_end; card++) {
		mi = card->modes;
		for (i = 0; i < card->nmodes; i++, mi++) {
			visible = mi->x && mi->y;
			if (!visible)
				continue; /* Hidden mode */
			if (!mi->depth)
				continue; /* I _think_ we need depth */
			if ((mi->x * mi->y * mi->depth) > res_max){
				res_max=(mi->x * mi->y * mi->depth);
				mode_max = mi->mode ? mi->mode : (mi->y << 8)+mi->x;
			}
		}
	}
return (mode_max)
}
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

akash_rawal
Posts: 229
Joined: Wed 25 Aug 2010, 15:38
Location: ISM Dhanbad, Jharkhand, India

#3 Post by akash_rawal »

I think the code should first try to guess the maximum resolution rather than asking the user. If that doesn't work, then ask the user.

I think set_mode() returns nonzero in case of failure.

Here's the function that finds maximum resolution available. If multiple modes with same resolution exist, one with maximum depth is selected.

Code: Select all

u16 guess_max_resolution(void)
{
	struct card_info *card;
	struct mode_info *mi;
	
	unsigned long long max_pixels = 0;
	unsigned int max_depth = 0;
	u16 sel_mode = 0;
	
	//Iterate for each mode
	for (card = video_cards; card < video_cards_end; card++)
	{
		int i;
		mi = card->modes;
		for (i = 0; i < card->nmodes; i++, mi++)
		{
			//Avoid 'hidden modes'
			int visible = mi->x && mi->y;
			if (!visible) continue;
			
			//Uncomment this if depth is required
			//if (! mi->depth) continue;
			
			unsigned long long one_pixels = mi->x * mi->y;
			u16 onemode = mi->mode ? mi->mode : (mi->y << 8) + mi->x;
			//Check whether this one is higher
			if (one_pixels > max_pixels)
			{
				//Select this one
				sel_mode = onemode;
				max_pixels = one_pixels;
				max_depth = mi->depth;
			}
			else if (one_pixels == max_pixels)
			{
				//Check for maximum depth
				if (mi->depth)
				{
					if (mi->depth > max_depth)
					{
						//Select this one
						sel_mode = onemode;
						max_depth = mi->depth;
					}
				}
			}
		}
	}
	
	return sel_mode;
}
It could be integrated like this:

Code: Select all

void set_video(void)
{
	...
	int not_guessed = 1;
	for (;;)
	{
		if (mode == ASK_VGA)
		{
			//If guessing maximum resolution hasn't been tried yet try it now
			if (not_guessed)
			{
				mode = guess_max_resolution();
				not_guessed = 0;
			}
			else
				mode = mode_menu();
		}
		
		if (!set_mode(mode))
			break;
		
		printf("Undefined video mode number: %x\n", mode);
		mode = ASK_VGA;
	}
	...
}

PANZERKOPF
Posts: 282
Joined: Wed 16 Dec 2009, 21:38
Location: Earth

Re: improve Xfbdev with kernel patch

#4 Post by PANZERKOPF »

technosaurus wrote: One of the things that makes Xorg a necessity is all of the manual kernel command line interaction by the user that is needed to set the resolution of the frame buffer.
It seems there is another way to get a working framebuffer. Kernel has several framebuffer modules for particular videocards (nvidiafb, radeonfb etc.). We can
boot in usual text mode, load a module, tune framebuffer with fbset utility then load Xfbdev server. I guess that framebuffer should be faster than VESA one.
SUUM CUIQUE.

User avatar
Iguleder
Posts: 2026
Joined: Tue 11 Aug 2009, 09:36
Location: Israel, somewhere in the beautiful desert
Contact:

#5 Post by Iguleder »

I wrote a similar patch for the 3.14.x "longterm" branch (using code from mode_menu(), with akash_rawal's patch as inspiration). I tried to keep the patch as short as possible.

The idea is to force a framebuffer console, to allow the use of Xfbdev instead of Xorg or Xvesa under KMS-incapable hardware. You can find the patch here:

Code: Select all

diff -rup linux-3.14.19-orig/arch/x86/boot/video.c linux-3.14.19/arch/x86/boot/video.c
--- linux-3.14.19-orig/arch/x86/boot/video.c	2014-09-21 20:11:20.662964171 +0300
+++ linux-3.14.19/arch/x86/boot/video.c	2014-09-22 19:22:39.520944994 +0300
@@ -312,6 +312,39 @@ static void restore_screen(void)
 	store_cursor_position();
 }
 
+static u16 guess_mode(void) {
+	int i;
+	unsigned long max_pixels = 0UL;
+	u16 max_depth = 0;
+	u16 mode = ASK_VGA;
+	struct card_info *card;
+	struct mode_info *mi;
+
+	for (card = video_cards; card < video_cards_end; card++) {
+		mi = card->modes;
+		for (i = 0; i < card->nmodes; i++, mi++) {
+			int visible = mi->x && mi->y;
+			u16 mode_id = mi->mode ? mi->mode :
+					(mi->y << 8)+mi->x;
+
+			if (!visible)
+				continue; /* Hidden mode */
+
+			unsigned long pixels = mi->x * mi->y;
+			if (pixels > max_pixels) {
+				max_pixels = pixels;
+				max_depth = mi->depth;
+				mode = mode_id;
+			} else if ((pixels == max_pixels) && (mi->depth > max_depth)) {
+				max_depth = mi->depth;
+				mode = mode_id;
+			}
+		}
+	}
+
+	return mode;
+}
+
 void set_video(void)
 {
 	u16 mode = boot_params.hdr.vid_mode;
@@ -322,6 +355,9 @@ void set_video(void)
 	save_screen();
 	probe_cards(0);
 
+	if (mode == ASK_VGA)
+		mode = guess_mode();
+
 	for (;;) {
 		if (mode == ASK_VGA)
 			mode = mode_menu();
[url=http://dimakrasner.com/]My homepage[/url]
[url=https://github.com/dimkr]My GitHub profile[/url]

Post Reply