Added support for parsing /etc/fb.modes, based on Stephane Marchesin's patch
authorSam Lantinga <slouken@libsdl.org>
Mon, 02 Jan 2006 09:08:05 +0000
changeset 1215d082d2d66ec8
parent 1214 31103dbf1c26
child 1216 f8fc6fdd589d
Added support for parsing /etc/fb.modes, based on Stephane Marchesin's patch
src/video/fbcon/SDL_fbvideo.c
     1.1 --- a/src/video/fbcon/SDL_fbvideo.c	Mon Jan 02 08:07:41 2006 +0000
     1.2 +++ b/src/video/fbcon/SDL_fbvideo.c	Mon Jan 02 09:08:05 2006 +0000
     1.3 @@ -51,6 +51,7 @@
     1.4  #include "SDL_fbmatrox.h"
     1.5  #include "SDL_fbriva.h"
     1.6  
     1.7 +/*#define FBCON_DEBUG*/
     1.8  
     1.9  #if defined(i386) && defined(FB_TYPE_VGA_PLANES)
    1.10  #define VGA16_FBCON_SUPPORT
    1.11 @@ -234,6 +235,108 @@
    1.12  	FB_Available, FB_CreateDevice
    1.13  };
    1.14  
    1.15 +#define FB_MODES_DB	"/etc/fb.modes"
    1.16 +
    1.17 +static int read_fbmodes_line(FILE*f, char* line, int length)
    1.18 +{
    1.19 +	int blank;
    1.20 +	char* c;
    1.21 +	int i;
    1.22 +	
    1.23 +	blank=0;
    1.24 +	/* find a relevant line */
    1.25 +	do
    1.26 +	{
    1.27 +		if (fgets(line,length,f)<=0)
    1.28 +			return 0;
    1.29 +		c=line;
    1.30 +		while(((*c=='\t')||(*c==' '))&&(*c!=0))
    1.31 +			c++;
    1.32 +		
    1.33 +		if ((*c=='\n')||(*c=='#')||(*c==0))
    1.34 +			blank=1;
    1.35 +		else
    1.36 +			blank=0;
    1.37 +	}
    1.38 +	while(blank);
    1.39 +	/* remove whitespace at the begining of the string */
    1.40 +	i=0;
    1.41 +	do
    1.42 +	{
    1.43 +		line[i]=c[i];
    1.44 +		i++;
    1.45 +	}
    1.46 +	while(c[i]!=0);
    1.47 +	return 1;
    1.48 +}
    1.49 +
    1.50 +static int read_fbmodes_mode(FILE *f, struct fb_var_screeninfo *vinfo)
    1.51 +{
    1.52 +	char line[1024];
    1.53 +	char option[256];
    1.54 +
    1.55 +	/* Find a "geometry" */
    1.56 +	do {
    1.57 +		if (read_fbmodes_line(f, line, sizeof(line))==0)
    1.58 +			return 0;
    1.59 +		if (strncmp(line,"geometry",8)==0)
    1.60 +			break;
    1.61 +	}
    1.62 +	while(1);
    1.63 +
    1.64 +	sscanf(line, "geometry %d %d %d %d %d", &vinfo->xres, &vinfo->yres, 
    1.65 +			&vinfo->xres_virtual, &vinfo->yres_virtual, &vinfo->bits_per_pixel);
    1.66 +	if (read_fbmodes_line(f, line, sizeof(line))==0)
    1.67 +		return 0;
    1.68 +			
    1.69 +	sscanf(line, "timings %d %d %d %d %d %d %d", &vinfo->pixclock, 
    1.70 +			&vinfo->left_margin, &vinfo->right_margin, &vinfo->upper_margin, 
    1.71 +			&vinfo->lower_margin, &vinfo->hsync_len, &vinfo->vsync_len);
    1.72 +		
    1.73 +	vinfo->sync=0;
    1.74 +	vinfo->vmode=FB_VMODE_NONINTERLACED;
    1.75 +				
    1.76 +	/* Parse misc options */
    1.77 +	do {
    1.78 +		if (read_fbmodes_line(f, line, sizeof(line))==0)
    1.79 +			return 0;
    1.80 +
    1.81 +		if (strncmp(line,"hsync",5)==0) {
    1.82 +			sscanf(line,"hsync %s",option);
    1.83 +			if (strncmp(option,"high",4)==0)
    1.84 +				vinfo->sync |= FB_SYNC_HOR_HIGH_ACT;
    1.85 +		}
    1.86 +		else if (strncmp(line,"vsync",5)==0) {
    1.87 +			sscanf(line,"vsync %s",option);
    1.88 +			if (strncmp(option,"high",4)==0)
    1.89 +				vinfo->sync |= FB_SYNC_VERT_HIGH_ACT;
    1.90 +		}
    1.91 +		else if (strncmp(line,"csync",5)==0) {
    1.92 +			sscanf(line,"csync %s",option);
    1.93 +			if (strncmp(option,"high",4)==0)
    1.94 +				vinfo->sync |= FB_SYNC_COMP_HIGH_ACT;
    1.95 +		}
    1.96 +		else if (strncmp(line,"extsync",5)==0) {
    1.97 +			sscanf(line,"extsync %s",option);
    1.98 +			if (strncmp(option,"true",4)==0)
    1.99 +				vinfo->sync |= FB_SYNC_EXT;
   1.100 +		}
   1.101 +		else if (strncmp(line,"laced",5)==0) {
   1.102 +			sscanf(line,"laced %s",option);
   1.103 +			if (strncmp(option,"true",4)==0)
   1.104 +				vinfo->vmode |= FB_VMODE_INTERLACED;
   1.105 +		}
   1.106 +		else if (strncmp(line,"double",6)==0) {
   1.107 +			sscanf(line,"double %s",option);
   1.108 +			if (strncmp(option,"true",4)==0)
   1.109 +				vinfo->vmode |= FB_VMODE_DOUBLE;
   1.110 +		}
   1.111 +	}
   1.112 +	while(strncmp(line,"endmode",7)!=0);
   1.113 +
   1.114 +	return 1;
   1.115 +}
   1.116 +
   1.117  static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo,
   1.118                          int index, unsigned int *w, unsigned int *h)
   1.119  {
   1.120 @@ -259,7 +362,7 @@
   1.121  	return mode_okay;
   1.122  }
   1.123  
   1.124 -static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h)
   1.125 +static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h, int check_timings)
   1.126  {
   1.127  	SDL_Rect *mode;
   1.128  	int i;
   1.129 @@ -277,19 +380,21 @@
   1.130  	}
   1.131  
   1.132  	/* Only allow a mode if we have a valid timing for it */
   1.133 -	next_mode = -1;
   1.134 -	for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
   1.135 -		if ( (w == vesa_timings[i].xres) &&
   1.136 -		     (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) {
   1.137 -			next_mode = i;
   1.138 -			break;
   1.139 +	if ( check_timings ) {
   1.140 +		int found_timing = 0;
   1.141 +		for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
   1.142 +			if ( (w == vesa_timings[i].xres) &&
   1.143 +			     (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) {
   1.144 +				found_timing = 1;
   1.145 +				break;
   1.146 +			}
   1.147  		}
   1.148 -	}
   1.149 -	if ( next_mode == -1 ) {
   1.150 +		if ( !found_timing ) {
   1.151  #ifdef FBCON_DEBUG
   1.152 -		fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h);
   1.153 +			fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h);
   1.154  #endif
   1.155 -		return(0);
   1.156 +			return(0);
   1.157 +		}
   1.158  	}
   1.159  
   1.160  	/* Set up the new video mode rectangle */
   1.161 @@ -323,6 +428,26 @@
   1.162  	return(0);
   1.163  }
   1.164  
   1.165 +static int cmpmodes(const void *va, const void *vb)
   1.166 +{
   1.167 +    const SDL_Rect *a = *(const SDL_Rect**)va;
   1.168 +    const SDL_Rect *b = *(const SDL_Rect**)vb;
   1.169 +    if ( a->h == b->h )
   1.170 +        return b->w - a->w;
   1.171 +    else
   1.172 +        return b->h - a->h;
   1.173 +}
   1.174 +
   1.175 +static int FB_SortModes(_THIS)
   1.176 +{
   1.177 +	int i;
   1.178 +	for ( i=0; i<NUM_MODELISTS; ++i ) {
   1.179 +		if ( SDL_nummodes[i] > 0 ) {
   1.180 +			qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes);
   1.181 +		}
   1.182 +	}
   1.183 +}
   1.184 +
   1.185  static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
   1.186  {
   1.187  	struct fb_fix_screeninfo finfo;
   1.188 @@ -332,6 +457,7 @@
   1.189  	unsigned int current_w;
   1.190  	unsigned int current_h;
   1.191  	const char *SDL_fbdev;
   1.192 +	FILE *modesdb;
   1.193  
   1.194  	/* Initialize the library */
   1.195  	SDL_fbdev = getenv("SDL_FBDEV");
   1.196 @@ -463,12 +589,37 @@
   1.197  	current_w = vinfo.xres;
   1.198  	current_h = vinfo.yres;
   1.199  	current_index = ((vinfo.bits_per_pixel+7)/8)-1;
   1.200 +	modesdb = fopen(FB_MODES_DB, "r");
   1.201 +	for ( i=0; i<NUM_MODELISTS; ++i ) {
   1.202 +		SDL_nummodes[i] = 0;
   1.203 +		SDL_modelist[i] = NULL;
   1.204 +	}
   1.205  	if ( getenv("SDL_FB_BROKEN_MODES") != NULL ) {
   1.206 -		FB_AddMode(this, current_index, current_w, current_h);
   1.207 +		FB_AddMode(this, current_index, current_w, current_h, 0);
   1.208 +	} else if(modesdb) {
   1.209 +		while ( read_fbmodes_mode(modesdb, &vinfo) ) {
   1.210 +			for ( i=0; i<NUM_MODELISTS; ++i ) {
   1.211 +				unsigned int w, h;
   1.212 +
   1.213 +				/* See if we are querying for the current mode */
   1.214 +				w = vinfo.xres;
   1.215 +				h = vinfo.yres;
   1.216 +				if ( i == current_index ) {
   1.217 +					if ( (current_w > w) || (current_h > h) ) {
   1.218 +						/* Only check once */
   1.219 +						FB_AddMode(this, i, current_w, current_h, 0);
   1.220 +						current_index = -1;
   1.221 +					}
   1.222 +				}
   1.223 +				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
   1.224 +					FB_AddMode(this, i, w, h, 0);
   1.225 +				}
   1.226 +			}
   1.227 +		}
   1.228 +		fclose(modesdb);
   1.229 +		FB_SortModes(this);
   1.230  	} else {
   1.231  		for ( i=0; i<NUM_MODELISTS; ++i ) {
   1.232 -			SDL_nummodes[i] = 0;
   1.233 -			SDL_modelist[i] = NULL;
   1.234  			for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) {
   1.235  				unsigned int w, h;
   1.236  
   1.237 @@ -478,12 +629,12 @@
   1.238  				if ( i == current_index ) {
   1.239  					if ( (current_w > w) || (current_h > h) ) {
   1.240  						/* Only check once */
   1.241 -						FB_AddMode(this, i, current_w, current_h);
   1.242 +						FB_AddMode(this, i, current_w, current_h, 0);
   1.243  						current_index = -1;
   1.244  					}
   1.245  				}
   1.246  				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
   1.247 -					FB_AddMode(this, i, w, h);
   1.248 +					FB_AddMode(this, i, w, h, 1);
   1.249  				}
   1.250  			}
   1.251  		}
   1.252 @@ -611,13 +762,21 @@
   1.253  static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo)
   1.254  {
   1.255  	int matched;
   1.256 -	FILE *fbmodes;
   1.257 +	FILE *modesdb;
   1.258 +	struct fb_var_screeninfo cinfo;
   1.259  
   1.260  	matched = 0;
   1.261 -	fbmodes = fopen("/etc/fb.modes", "r");
   1.262 -	if ( fbmodes ) {
   1.263 -		/* FIXME: Parse the mode definition file */
   1.264 -		fclose(fbmodes);
   1.265 +	modesdb = fopen(FB_MODES_DB, "r");
   1.266 +	if ( modesdb ) {
   1.267 +		/* Parse the mode definition file */
   1.268 +		while ( read_fbmodes_mode(modesdb, &cinfo) ) {
   1.269 +			if ( vinfo->xres == cinfo.xres &&
   1.270 +			     vinfo->yres == cinfo.yres ) {
   1.271 +				matched = 1;
   1.272 +				break;
   1.273 +			}
   1.274 +		}
   1.275 +		fclose(modesdb);
   1.276  	}
   1.277  	return(matched);
   1.278  }