From 0e9fd6626dbd5ff71e2aebf4647bf728479b3b9c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 2 Jan 2006 09:08:05 +0000 Subject: [PATCH] Added support for parsing /etc/fb.modes, based on Stephane Marchesin's patch --- src/video/fbcon/SDL_fbvideo.c | 201 ++++++++++++++++++++++++++++++---- 1 file changed, 180 insertions(+), 21 deletions(-) diff --git a/src/video/fbcon/SDL_fbvideo.c b/src/video/fbcon/SDL_fbvideo.c index edee92026..e2522328f 100644 --- a/src/video/fbcon/SDL_fbvideo.c +++ b/src/video/fbcon/SDL_fbvideo.c @@ -51,6 +51,7 @@ static char rcsid = #include "SDL_fbmatrox.h" #include "SDL_fbriva.h" +/*#define FBCON_DEBUG*/ #if defined(i386) && defined(FB_TYPE_VGA_PLANES) #define VGA16_FBCON_SUPPORT @@ -234,6 +235,108 @@ VideoBootStrap FBCON_bootstrap = { FB_Available, FB_CreateDevice }; +#define FB_MODES_DB "/etc/fb.modes" + +static int read_fbmodes_line(FILE*f, char* line, int length) +{ + int blank; + char* c; + int i; + + blank=0; + /* find a relevant line */ + do + { + if (fgets(line,length,f)<=0) + return 0; + c=line; + while(((*c=='\t')||(*c==' '))&&(*c!=0)) + c++; + + if ((*c=='\n')||(*c=='#')||(*c==0)) + blank=1; + else + blank=0; + } + while(blank); + /* remove whitespace at the begining of the string */ + i=0; + do + { + line[i]=c[i]; + i++; + } + while(c[i]!=0); + return 1; +} + +static int read_fbmodes_mode(FILE *f, struct fb_var_screeninfo *vinfo) +{ + char line[1024]; + char option[256]; + + /* Find a "geometry" */ + do { + if (read_fbmodes_line(f, line, sizeof(line))==0) + return 0; + if (strncmp(line,"geometry",8)==0) + break; + } + while(1); + + sscanf(line, "geometry %d %d %d %d %d", &vinfo->xres, &vinfo->yres, + &vinfo->xres_virtual, &vinfo->yres_virtual, &vinfo->bits_per_pixel); + if (read_fbmodes_line(f, line, sizeof(line))==0) + return 0; + + sscanf(line, "timings %d %d %d %d %d %d %d", &vinfo->pixclock, + &vinfo->left_margin, &vinfo->right_margin, &vinfo->upper_margin, + &vinfo->lower_margin, &vinfo->hsync_len, &vinfo->vsync_len); + + vinfo->sync=0; + vinfo->vmode=FB_VMODE_NONINTERLACED; + + /* Parse misc options */ + do { + if (read_fbmodes_line(f, line, sizeof(line))==0) + return 0; + + if (strncmp(line,"hsync",5)==0) { + sscanf(line,"hsync %s",option); + if (strncmp(option,"high",4)==0) + vinfo->sync |= FB_SYNC_HOR_HIGH_ACT; + } + else if (strncmp(line,"vsync",5)==0) { + sscanf(line,"vsync %s",option); + if (strncmp(option,"high",4)==0) + vinfo->sync |= FB_SYNC_VERT_HIGH_ACT; + } + else if (strncmp(line,"csync",5)==0) { + sscanf(line,"csync %s",option); + if (strncmp(option,"high",4)==0) + vinfo->sync |= FB_SYNC_COMP_HIGH_ACT; + } + else if (strncmp(line,"extsync",5)==0) { + sscanf(line,"extsync %s",option); + if (strncmp(option,"true",4)==0) + vinfo->sync |= FB_SYNC_EXT; + } + else if (strncmp(line,"laced",5)==0) { + sscanf(line,"laced %s",option); + if (strncmp(option,"true",4)==0) + vinfo->vmode |= FB_VMODE_INTERLACED; + } + else if (strncmp(line,"double",6)==0) { + sscanf(line,"double %s",option); + if (strncmp(option,"true",4)==0) + vinfo->vmode |= FB_VMODE_DOUBLE; + } + } + while(strncmp(line,"endmode",7)!=0); + + return 1; +} + static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo, int index, unsigned int *w, unsigned int *h) { @@ -259,7 +362,7 @@ static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo, return mode_okay; } -static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h) +static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h, int check_timings) { SDL_Rect *mode; int i; @@ -277,19 +380,21 @@ static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h) } /* Only allow a mode if we have a valid timing for it */ - next_mode = -1; - for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) { - if ( (w == vesa_timings[i].xres) && - (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) { - next_mode = i; - break; + if ( check_timings ) { + int found_timing = 0; + for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) { + if ( (w == vesa_timings[i].xres) && + (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) { + found_timing = 1; + break; + } } - } - if ( next_mode == -1 ) { + if ( !found_timing ) { #ifdef FBCON_DEBUG - fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h); + fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h); #endif - return(0); + return(0); + } } /* Set up the new video mode rectangle */ @@ -323,6 +428,26 @@ static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h) return(0); } +static int cmpmodes(const void *va, const void *vb) +{ + const SDL_Rect *a = *(const SDL_Rect**)va; + const SDL_Rect *b = *(const SDL_Rect**)vb; + if ( a->h == b->h ) + return b->w - a->w; + else + return b->h - a->h; +} + +static int FB_SortModes(_THIS) +{ + int i; + for ( i=0; i 0 ) { + qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes); + } + } +} + static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat) { struct fb_fix_screeninfo finfo; @@ -332,6 +457,7 @@ static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat) unsigned int current_w; unsigned int current_h; const char *SDL_fbdev; + FILE *modesdb; /* Initialize the library */ SDL_fbdev = getenv("SDL_FBDEV"); @@ -463,12 +589,37 @@ static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat) current_w = vinfo.xres; current_h = vinfo.yres; current_index = ((vinfo.bits_per_pixel+7)/8)-1; + modesdb = fopen(FB_MODES_DB, "r"); + for ( i=0; i w) || (current_h > h) ) { + /* Only check once */ + FB_AddMode(this, i, current_w, current_h, 0); + current_index = -1; + } + } + if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) { + FB_AddMode(this, i, w, h, 0); + } + } + } + fclose(modesdb); + FB_SortModes(this); } else { for ( i=0; i w) || (current_h > h) ) { /* Only check once */ - FB_AddMode(this, i, current_w, current_h); + FB_AddMode(this, i, current_w, current_h, 0); current_index = -1; } } if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) { - FB_AddMode(this, i, w, h); + FB_AddMode(this, i, w, h, 1); } } } @@ -611,13 +762,21 @@ static void print_finfo(struct fb_fix_screeninfo *finfo) static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo) { int matched; - FILE *fbmodes; + FILE *modesdb; + struct fb_var_screeninfo cinfo; matched = 0; - fbmodes = fopen("/etc/fb.modes", "r"); - if ( fbmodes ) { - /* FIXME: Parse the mode definition file */ - fclose(fbmodes); + modesdb = fopen(FB_MODES_DB, "r"); + if ( modesdb ) { + /* Parse the mode definition file */ + while ( read_fbmodes_mode(modesdb, &cinfo) ) { + if ( vinfo->xres == cinfo.xres && + vinfo->yres == cinfo.yres ) { + matched = 1; + break; + } + } + fclose(modesdb); } return(matched); }