From ff12a738b591f7a0874a22cc51fcace9c97022f6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Feb 2001 05:56:53 +0000 Subject: [PATCH] Linux frame buffer support from Ryan Nielsen (thank you). While not yet fully functional, it compiles and runs to the point of failing to find a mode (probably my fault, that:), but there's no mouse support yet and the keyboard input isn't playable. --- configure.in | 27 +- include/fbset.h | 84 ++++ include/vid.h | 3 +- source/.gitignore | 4 + source/Makefile.am | 24 +- source/fbset.c | 1065 ++++++++++++++++++++++++++++++++++++++++ source/fbset_modes_l.l | 138 ++++++ source/fbset_modes_y.y | 176 +++++++ source/in_fbdev.c | 154 ++++++ source/vid_fbdev.c | 705 ++++++++++++++++++++++++++ 10 files changed, 2374 insertions(+), 6 deletions(-) create mode 100644 include/fbset.h create mode 100644 source/fbset.c create mode 100644 source/fbset_modes_l.l create mode 100644 source/fbset_modes_y.y create mode 100644 source/in_fbdev.c create mode 100644 source/vid_fbdev.c diff --git a/configure.in b/configure.in index 81cd5ed..434399b 100644 --- a/configure.in +++ b/configure.in @@ -54,6 +54,11 @@ AC_PROG_CC AC_PROG_CPP AC_PROG_LN_S AC_PROG_RANLIB +AM_PROG_LEX +AC_PROG_YACC + +AC_CHECK_LIB(l, main, LEXLIB="-ll", AC_CHECK_LIB(fl, main, LEXLIB="-lfl")) +AC_SUBST(LEXLIB) set $CC if test "$1" = gcc; then @@ -376,6 +381,17 @@ AC_SUBST(HAVE_GGI) AC_SUBST(GGI_CFLAGS) AC_SUBST(GGI_LIBS) +dnl Checks for Linux FBDev support +AC_ARG_WITH(fbdev, +[ --with-fbdev use Linux framebuffer device], +HAVE_FBDEV=$withval, HAVE_FBDEV=auto) +if test "x$HAVE_FBDEV" != xno; then + dnl We should still be able to compile it even if + dnl there is no fbdev support in the running kernel + AC_CHECK_HEADER(linux/fb.h, HAVE_FBDEV=yes, HAVE_FBDEV=no) +fi +AC_SUBST(HAVE_FBDEV) + dnl Checks for SVGALib support AC_ARG_WITH(svga, [ --with-svga[=DIR] use SVGALib found in DIR], @@ -1230,12 +1246,13 @@ dnl ================================================================== AC_ARG_WITH(clients, [ --with-clients= compile clients in ; - 3dfx,ggi,glx,mgl,sdl,sgl,svga,x11], + 3dfx,fbdev,ggi,glx,mgl,sdl,sgl,svga,x11], clients="$withval", clients="all" ) if test "$clients" = "all"; then ENABLE_3DFX=yes + ENABLE_FBDEV=yes ENABLE_GGI=yes ENABLE_GLX=yes ENABLE_MGL=yes @@ -1245,6 +1262,7 @@ if test "$clients" = "all"; then ENABLE_X11=yes else ENABLE_3DFX=no + ENABLE_FBDEV=no ENABLE_GGI=no ENABLE_GLX=no ENABLE_MGL=no @@ -1258,6 +1276,9 @@ else 3dfx) ENABLE_3DFX=yes ;; + fbdev) + ENABLE_FBDEV=yes + ;; ggi) ENABLE_GGI=yes ;; @@ -1295,6 +1316,10 @@ if test "x$HAVE_TDFXGL" = xyes -a "x$ENABLE_3DFX" = xyes; then TARGETS="$TARGETS qf-client-3dfx\$(EXEEXT)" CL_TARGETS="$CL_TARGETS 3dfx" fi +if test "x$HAVE_FBDEV" = xyes -a "x$ENABLE_FBDEV" = xyes; then + TARGETS="$TARGETS qf-client-fbdev\$(EXEEXT)" + CL_TARGETS="$CL_TARGETS FBDEV" +fi if test "x$HAVE_GGI" = xyes -a "x$ENABLE_GGI" = xyes; then TARGETS="$TARGETS qf-client-ggi\$(EXEEXT)" CL_TARGETS="$CL_TARGETS GGI" diff --git a/include/fbset.h b/include/fbset.h new file mode 100644 index 0000000..b0f6a85 --- /dev/null +++ b/include/fbset.h @@ -0,0 +1,84 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +#include +#include + +#ifdef __GLIBC__ +#include +#endif + +#include + +#define FBSET_VERSION "Linux Frame Buffer Device Configuration " \ + "Version 2.1 (23/06/1999)\n" \ + "(C) Copyright 1995-1999 by Geert Uytterhoeven\n" + +#define LOW (0) +#define HIGH (1) + +#define FALSE (0) +#define TRUE (1) + +struct color { + unsigned int length; + unsigned int offset; +}; + +struct VideoMode { + struct VideoMode *next; + char *name; + /* geometry */ + __u32 xres; + __u32 yres; + __u32 vxres; + __u32 vyres; + __u32 depth; + __u32 nonstd; + /* acceleration */ + __u32 accel_flags; + /* timings */ + __u32 pixclock; + __u32 left; + __u32 right; + __u32 upper; + __u32 lower; + __u32 hslen; + __u32 vslen; + /* flags */ + unsigned hsync : 1; + unsigned vsync : 1; + unsigned csync : 1; + unsigned gsync : 1; + unsigned extsync : 1; + unsigned bcast : 1; + unsigned laced : 1; + unsigned dblscan : 1; + unsigned grayscale : 1; + /* scanrates */ + double drate; + double hrate; + double vrate; + /* RGB entries */ + struct color red, green, blue, transp; +}; + +extern FILE *yyin; +extern int line; +extern const char *Opt_modedb; + +extern int yyparse(void); +extern void Die(const char *fmt, ...) __attribute__ ((noreturn)); +extern void AddVideoMode(const struct VideoMode *vmode); +extern void makeRGBA(struct VideoMode *vmode, const char* opt); diff --git a/include/vid.h b/include/vid.h index 3d40d3b..1d85746 100644 --- a/include/vid.h +++ b/include/vid.h @@ -87,7 +87,8 @@ void VID_Update (vrect_t *rects); // sets the mode; only used by the Quake engine for resetting to mode 0 (the // base mode) on memory allocation failures -int VID_SetMode (int modenum, unsigned char *palette); +// or not +// int VID_SetMode (int modenum, unsigned char *palette); // called only on Win32, when pause happens, so the mouse can be released void VID_HandlePause (qboolean pause); diff --git a/source/.gitignore b/source/.gitignore index bb6408a..3d7f68a 100644 --- a/source/.gitignore +++ b/source/.gitignore @@ -41,3 +41,7 @@ qwaq-client-x11 qwaq-client-x11.exe qwaq-server qwaq-server.exe +fbset_modes_y.c +fbset_modes_y.h +fbset_modes_l.c +qf-client-fbdev diff --git a/source/Makefile.am b/source/Makefile.am index ef515f4..c51320f 100644 --- a/source/Makefile.am +++ b/source/Makefile.am @@ -36,9 +36,9 @@ INCLUDES= -I$(top_srcdir)/include $(GGI_CFLAGS) $(MGL_CFLAGS) $(SDL_CFLAGS) $(SV bin_PROGRAMS = @TARGETS@ EXTRA_PROGRAMS= qf-server \ - qf-client-3dfx qf-client-ggi qf-client-glx qf-client-mgl \ - qf-client-sdl qf-client-sgl qf-client-svga qf-client-wgl \ - qf-client-x11 + qf-client-3dfx qf-client-fbdev qf-client-ggi qf-client-glx \ + qf-client-mgl qf-client-sdl qf-client-sgl qf-client-svga \ + qf-client-wgl qf-client-x11 noinst_LIBRARIES= libqfcd.a libqfjs.a libqfnet.a libqfsnd.a libqfsys_cl.a libqfsys_sv.a @@ -200,6 +200,22 @@ soft_SOURCES= d_edge.c d_fill.c d_init.c d_modech.c \ screen.c $(soft_ASM) sw_model_alias.c sw_model_brush.c \ sw_model_sprite.c +# +# ... Linux FBDev +# +YFLAGS = -d +fbdev_SOURCES= fbset.c fbset_modes_y.y fbset_modes_l.l vid_fbdev.c in_fbdev.c +YACCLEX_CLEANFILES= fbset_modes_y.c fbset_modes_y.h fbset_modes_y.tab.h fbset_modes_l.c + +fbset_modes_y.o: fbset_modes_y.c + $(CC) $(INCLUDES) $(CFLAGS) -Wno-error -c fbset_modes_y.c +fbset_modes_l.o: fbset_modes_l.c + $(CC) $(INCLUDES) $(CFLAGS) -Wno-error -c fbset_modes_l.c + +qf_client_fbdev_SOURCES= $(common_SOURCES) $(client_SOURCES) $(soft_SOURCES) $(fbdev_SOURCES) +qf_client_fbdev_LDADD= $(CLIENT_LIBS) +qf_client_fbdev_DEPENDENCIES=libqfnet.a libqfsys_cl.a libqfsnd.a libqfcd.a libqfjs.a + # # ... GGI # @@ -304,4 +320,4 @@ EXTRA_DIST= makefile.win \ qf-client-sgl.mak qf-client-wgl.mak qf-client-win.mak # Kill the temp files, hopefully. -CLEANFILES = *.i *.s +CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES) diff --git a/source/fbset.c b/source/fbset.c new file mode 100644 index 0000000..db8f4ff --- /dev/null +++ b/source/fbset.c @@ -0,0 +1,1065 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1999 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + * + * Petr Vandrovec : + * -grayscale, -rgba, -nonstd, VGA modes reporting + * + * Brad Midgley : + * -match + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct file; +struct inode; + +#include "fbset.h" + + + /* + * Default Frame Buffer Special Device Node + */ + +#define DEFAULT_FRAMEBUFFER "/dev/fb0" + + + /* + * Default Video Mode Database File + */ + +#define DEFAULT_MODEDBFILE "/etc/fb.modes" + + /* + * Command Line Options + */ + +static const char *ProgramName; + +static int Opt_test = 0; +static int Opt_show = 0; +static int Opt_info = 0; +static int Opt_version = 0; +static int Opt_verbose = 0; +static int Opt_xfree86 = 0; +static int Opt_change = 0; +static int Opt_all = 0; + +static const char *Opt_fb = NULL; +const char *Opt_modedb = DEFAULT_MODEDBFILE; +static const char *Opt_xres = NULL; +static const char *Opt_yres = NULL; +static const char *Opt_vxres = NULL; +static const char *Opt_vyres = NULL; +static const char *Opt_depth = NULL; +static const char *Opt_pixclock = NULL; +static const char *Opt_left = NULL; +static const char *Opt_right = NULL; +static const char *Opt_upper = NULL; +static const char *Opt_lower = NULL; +static const char *Opt_hslen = NULL; +static const char *Opt_vslen = NULL; +static const char *Opt_accel = NULL; +static const char *Opt_hsync = NULL; +static const char *Opt_vsync = NULL; +static const char *Opt_csync = NULL; +static const char *Opt_gsync = NULL; +static const char *Opt_extsync = NULL; +static const char *Opt_bcast = NULL; +static const char *Opt_laced = NULL; +static const char *Opt_double = NULL; +static const char *Opt_move = NULL; +static const char *Opt_step = NULL; +static const char *Opt_modename = NULL; +static const char *Opt_rgba = NULL; +static const char *Opt_nonstd = NULL; +static const char *Opt_grayscale = NULL; +static const char *Opt_matchyres = NULL; + +static struct { + const char *name; + const char **value; + const int change; +} Options[] = { + { "-fb", &Opt_fb, 0 }, + { "-db", &Opt_modedb, 0 }, + { "-xres", &Opt_xres, 1 }, + { "-yres", &Opt_yres, 1 }, + { "-vxres", &Opt_vxres, 1 }, + { "-vyres", &Opt_vyres, 1 }, + { "-depth", &Opt_depth, 1 }, + { "-nonstd", &Opt_nonstd, 1}, + { "-pixclock", &Opt_pixclock, 1 }, + { "-left", &Opt_left, 1 }, + { "-right", &Opt_right, 1 }, + { "-upper", &Opt_upper, 1 }, + { "-lower", &Opt_lower, 1 }, + { "-hslen", &Opt_hslen, 1 }, + { "-vslen", &Opt_vslen, 1 }, + { "-accel", &Opt_accel, 1 }, + { "-hsync", &Opt_hsync, 1 }, + { "-vsync", &Opt_vsync, 1 }, + { "-csync", &Opt_csync, 1 }, + { "-gsync", &Opt_gsync, 1 }, + { "-extsync", &Opt_extsync, 1 }, + { "-bcast", &Opt_bcast, 1 }, + { "-laced", &Opt_laced, 1 }, + { "-double", &Opt_double, 1 }, + { "-move", &Opt_move, 1 }, + { "-step", &Opt_step, 1 }, + { "-rgba", &Opt_rgba, 1 }, + { "-grayscale", &Opt_grayscale, 1 }, + { NULL, NULL, 0 } +}; + + /* + * Video Mode Database + */ + +struct VideoMode *VideoModes = NULL; + + + /* + * Hardware Text Modes + */ + +static struct textentry { + __u32 id; + const char *name; +} Textmodes[] = { + { FB_AUX_TEXT_MDA, "Monochrome text" }, + { FB_AUX_TEXT_CGA, "CGA/EGA/VGA Color text" }, + { FB_AUX_TEXT_S3_MMIO, "S3 MMIO fasttext" }, + { FB_AUX_TEXT_MGA_STEP16, "MGA Millennium I step 16 text" }, + { FB_AUX_TEXT_MGA_STEP8, "MGA step 8 text" }, +}; + +static struct textentry VGAModes[] = { +// { FB_AUX_VGA_PLANES_VGA4, "VGA 16 colors in 4 planes" }, +// { FB_AUX_VGA_PLANES_CFB4, "VGA 16 colors in 1 plane" }, +// { FB_AUX_VGA_PLANES_CFB8, "VGA 256 colors in 4 planes" }, + /* last entry has name == NULL */ + { 0, NULL} +}; + + /* + * Hardware Accelerators + */ + +static struct accelentry { + __u32 id; + const char *name; +} Accelerators[] = { + { FB_ACCEL_NONE, "No" }, + { FB_ACCEL_ATARIBLITT, "Atari Blitter" }, + { FB_ACCEL_AMIGABLITT, "Amiga Blitter" }, + { FB_ACCEL_S3_TRIO64, "S3 Trio64" }, + { FB_ACCEL_NCR_77C32BLT, "NCR 77C32BLT" }, + { FB_ACCEL_S3_VIRGE, "S3 ViRGE" }, + { FB_ACCEL_ATI_MACH64GX, "ATI Mach64GX" }, + { FB_ACCEL_DEC_TGA, "DEC 21030 TGA" }, + { FB_ACCEL_ATI_MACH64CT, "ATI Mach64CT" }, + { FB_ACCEL_ATI_MACH64VT, "ATI Mach64VT" }, + { FB_ACCEL_ATI_MACH64GT, "ATI Mach64GT" }, + { FB_ACCEL_SUN_CREATOR, "Sun Creator/Creator3D" }, + { FB_ACCEL_SUN_CGSIX, "Sun cg6" }, + { FB_ACCEL_SUN_LEO, "Sun leo/zx" }, + { FB_ACCEL_IMS_TWINTURBO, "IMS Twin Turbo" }, + { FB_ACCEL_3DLABS_PERMEDIA2, "3Dlabs Permedia 2" }, + { FB_ACCEL_MATROX_MGA2064W, "Matrox MGA2064W (Millennium)" }, + { FB_ACCEL_MATROX_MGA1064SG, "Matrox MGA1064SG (Mystique)" }, + { FB_ACCEL_MATROX_MGA2164W, "Matrox MGA2164W (Millennium II)" }, + { FB_ACCEL_MATROX_MGA2164W_AGP, "Matrox MGA2164W (Millennium II AGP)" }, + { FB_ACCEL_MATROX_MGAG100, "Matrox G100 (Productiva G100)" }, + { FB_ACCEL_MATROX_MGAG200, "Matrox G200 (Millennium, Mystique)" }, + { FB_ACCEL_SUN_CG14, "Sun cg14" }, + { FB_ACCEL_SUN_BWTWO, "Sun bw2" }, + { FB_ACCEL_SUN_CGTHREE, "Sun cg3" }, + { FB_ACCEL_SUN_TCX, "Sun tcx" }, + { FB_ACCEL_MATROX_MGAG400, "Matrox G400" }, +}; + + + /* + * Current Video Mode + */ + +struct VideoMode Current; + + + /* + * Function Prototypes + */ + +int OpenFrameBuffer(const char *name); +void CloseFrameBuffer(int fh); +int GetVarScreenInfo(int fh, struct fb_var_screeninfo *var); +int SetVarScreenInfo(int fh, struct fb_var_screeninfo *var); +int GetFixScreenInfo(int fh, struct fb_fix_screeninfo *fix); +void ConvertFromVideoMode(const struct VideoMode *vmode, + struct fb_var_screeninfo *var); +void ConvertToVideoMode(const struct fb_var_screeninfo *var, + struct VideoMode *vmode); +static int atoboolean(const char *var); +void ReadModeDB(void); +struct VideoMode *FindVideoMode(const char *name); +static void ModifyVideoMode(struct VideoMode *vmode); +static void DisplayVModeInfo(struct VideoMode *vmode); +static void DisplayFBInfo(struct fb_fix_screeninfo *fix); +static int FillScanRates(struct VideoMode *vmode); +static void Usage(void); +int main(int argc, char *argv[]); + +extern void Con_Printf (const char *fmt, ...); + +#define Die Con_Printf +#define puts(s) Con_Printf("%s\n",(s)) +#define printf Con_Printf + + /* + * Open the Frame Buffer Device + */ + +int OpenFrameBuffer(const char *name) +{ + int fh; + + if (Opt_verbose) + printf("Opening frame buffer device `%s'\n", name); + + if ((fh = open(name, O_RDWR)) == -1) + Die("open %s: %s\n", name, strerror(errno)); + return fh; +} + + + /* + * Close the Frame Buffer Device + */ + +void CloseFrameBuffer(int fh) +{ + close(fh); +} + + /* + * Get the Variable Part of the Screen Info + */ + +int GetVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOGET_VSCREENINFO, var)) { + Die("ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno)); + return -1; + } + return 0; +} + + + /* + * Set (and Get) the Variable Part of the Screen Info + */ + +int SetVarScreenInfo(int fh, struct fb_var_screeninfo *var) +{ + if (ioctl(fh, FBIOPUT_VSCREENINFO, var)) { + Die("ioctl FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); + return -1; + } + return 0; +} + + + /* + * Get the Fixed Part of the Screen Info + */ + +int GetFixScreenInfo(int fh, struct fb_fix_screeninfo *fix) +{ + if (ioctl(fh, FBIOGET_FSCREENINFO, fix)) { + Die("ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno)); + return -1; + } + return 0; +} + + + /* + * Conversion Routines + */ + +void ConvertFromVideoMode(const struct VideoMode *vmode, + struct fb_var_screeninfo *var) +{ + memset(var, 0, sizeof(struct fb_var_screeninfo)); + var->xres = vmode->xres; + var->yres = vmode->yres; + var->xres_virtual = vmode->vxres; + var->yres_virtual = vmode->vyres; + var->bits_per_pixel = vmode->depth; + var->nonstd = vmode->nonstd; + if (Opt_test) + var->activate = FB_ACTIVATE_TEST; + else + var->activate = FB_ACTIVATE_NOW; + if (Opt_all) + var->activate = FB_ACTIVATE_ALL; + var->accel_flags = vmode->accel_flags; + var->pixclock = vmode->pixclock; + var->left_margin = vmode->left; + var->right_margin = vmode->right; + var->upper_margin = vmode->upper; + var->lower_margin = vmode->lower; + var->hsync_len = vmode->hslen; + var->vsync_len = vmode->vslen; + if (vmode->hsync == HIGH) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (vmode->vsync == HIGH) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (vmode->csync == HIGH) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + if (vmode->gsync == HIGH) + var->sync |= FB_SYNC_ON_GREEN; + if (vmode->extsync == TRUE) + var->sync |= FB_SYNC_EXT; + if (vmode->bcast == TRUE) + var->sync |= FB_SYNC_BROADCAST; + if (vmode->laced == TRUE) + var->vmode = FB_VMODE_INTERLACED; + else if (vmode->dblscan == TRUE) + var->vmode = FB_VMODE_DOUBLE; + else + var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_CONUPDATE; + var->red.length = vmode->red.length; + var->red.offset = vmode->red.offset; + var->green.length = vmode->green.length; + var->green.offset = vmode->green.offset; + var->blue.length = vmode->blue.length; + var->blue.offset = vmode->blue.offset; + var->transp.length = vmode->transp.length; + var->transp.offset = vmode->transp.offset; + var->grayscale = vmode->grayscale; +} + + +void ConvertToVideoMode(const struct fb_var_screeninfo *var, + struct VideoMode *vmode) +{ + vmode->name = NULL; + vmode->xres = var->xres; + vmode->yres = var->yres; + vmode->vxres = var->xres_virtual; + vmode->vyres = var->yres_virtual; + vmode->depth = var->bits_per_pixel; + vmode->nonstd = var->nonstd; + vmode->accel_flags = var->accel_flags; + vmode->pixclock = var->pixclock; + vmode->left = var->left_margin; + vmode->right = var->right_margin; + vmode->upper = var->upper_margin; + vmode->lower = var->lower_margin; + vmode->hslen = var->hsync_len; + vmode->vslen = var->vsync_len; + vmode->hsync = var->sync & FB_SYNC_HOR_HIGH_ACT ? HIGH : LOW; + vmode->vsync = var->sync & FB_SYNC_VERT_HIGH_ACT ? HIGH : LOW; + vmode->csync = var->sync & FB_SYNC_COMP_HIGH_ACT ? HIGH : LOW; + vmode->gsync = var->sync & FB_SYNC_ON_GREEN ? TRUE : FALSE; + vmode->extsync = var->sync & FB_SYNC_EXT ? TRUE : FALSE; + vmode->bcast = var->sync & FB_SYNC_BROADCAST ? TRUE : FALSE; + vmode->grayscale = var->grayscale; + vmode->laced = FALSE; + vmode->dblscan = FALSE; + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + vmode->laced = TRUE; + break; + case FB_VMODE_DOUBLE: + vmode->dblscan = TRUE; + break; + } + vmode->red.length = var->red.length; + vmode->red.offset = var->red.offset; + vmode->green.length = var->green.length; + vmode->green.offset = var->green.offset; + vmode->blue.length = var->blue.length; + vmode->blue.offset = var->blue.offset; + vmode->transp.length = var->transp.length; + vmode->transp.offset = var->transp.offset; + FillScanRates(vmode); +} + + +static int atoboolean(const char *var) +{ + int value = 0; + + if (!strcasecmp(var, "false") || !strcasecmp(var, "low") || + !strcasecmp(var, "no") || !strcasecmp(var, "off") || + !strcmp(var, "0")) + value = 0; + else if (!strcasecmp(var, "true") || !strcasecmp(var, "high") || + !strcasecmp(var, "yes") || !strcasecmp(var, "on") || + !strcmp(var, "1")) + value = 1; + else + Die("Invalid value `%s'\n", var); + + return value; +} + + +void AddVideoMode(const struct VideoMode *vmode) +{ + struct VideoMode *vmode2; + + if (FindVideoMode(vmode->name)) + Die("%s:%d: Duplicate mode name `%s'\n", Opt_modedb, line, + vmode->name); + vmode2 = malloc(sizeof(struct VideoMode)); + *vmode2 = *vmode; + if (!FillScanRates(vmode2)) + Die("%s:%d: Bad video mode `%s'\n", Opt_modedb, line, vmode2->name); + vmode2->next = VideoModes; + VideoModes = vmode2; +} + + + /* + * Read the Video Mode Database + */ + +void ReadModeDB(void) +{ + if (Opt_verbose) + printf("Reading mode database from file `%s'\n", Opt_modedb); + + if (!(yyin = fopen(Opt_modedb, "r"))) { + Die("fopen %s: %s\n", Opt_modedb, strerror(errno)); + return; + } + yyparse(); + fclose(yyin); +} + + +static void getColor(struct color *color, const char** opt) +{ + char* ptr; + + color->length = 0; + color->offset = 0; + ptr = (char*)(*opt); + if (!ptr) + return; + color->length = strtoul(ptr, &ptr, 0); + if (!ptr) + return; + if (*ptr == '/') + color->offset = strtoul(ptr+1, &ptr, 0); + if (ptr) { + while (*ptr && isspace(*ptr)) + ptr++; + if (*ptr == ',') { + ptr++; + } else if (*ptr) + Die("Bad RGBA syntax, rL/rO,gL/gO,bL/bO,tL/tO or rL,gL,bL,tL\n"); + } + *opt = ptr; + return; +} + +void makeRGBA(struct VideoMode *vmode, const char* opt) +{ + getColor(&vmode->red, &opt); + getColor(&vmode->green, &opt); + getColor(&vmode->blue, &opt); + getColor(&vmode->transp, &opt); +} + + /* + * Find a Video Mode + */ + +struct VideoMode *FindVideoMode(const char *name) +{ + struct VideoMode *vmode; + + for (vmode = VideoModes; vmode; vmode = vmode->next) + if (!strcmp(name, vmode->name)) + break; + + return vmode; +} + + + /* + * Modify a Video Mode + */ + +static void ModifyVideoMode(struct VideoMode *vmode) +{ + u_int hstep = 8, vstep = 2; + + if (Opt_xres) + vmode->xres = strtoul(Opt_xres, NULL, 0); + if (Opt_yres) + vmode->yres = strtoul(Opt_yres, NULL, 0); + if (Opt_vxres) + vmode->vxres = strtoul(Opt_vxres, NULL, 0); + if (Opt_vyres) + vmode->vyres = strtoul(Opt_vyres, NULL, 0); + if (Opt_depth) + vmode->depth = strtoul(Opt_depth, NULL, 0); + if (Opt_nonstd) + vmode->nonstd = strtoul(Opt_nonstd, NULL, 0); + if (Opt_accel) + vmode->accel_flags = atoboolean(Opt_accel) ? FB_ACCELF_TEXT : 0; + if (Opt_pixclock) + vmode->pixclock = strtoul(Opt_pixclock, NULL, 0); + if (Opt_left) + vmode->left = strtoul(Opt_left, NULL, 0); + if (Opt_right) + vmode->right = strtoul(Opt_right, NULL, 0); + if (Opt_upper) + vmode->upper = strtoul(Opt_upper, NULL, 0); + if (Opt_lower) + vmode->lower = strtoul(Opt_lower, NULL, 0); + if (Opt_hslen) + vmode->hslen = strtoul(Opt_hslen, NULL, 0); + if (Opt_vslen) + vmode->vslen = strtoul(Opt_vslen, NULL, 0); + if (Opt_hsync) + vmode->hsync = atoboolean(Opt_hsync); + if (Opt_vsync) + vmode->vsync = atoboolean(Opt_vsync); + if (Opt_csync) + vmode->csync = atoboolean(Opt_csync); + if (Opt_gsync) + vmode->gsync = atoboolean(Opt_gsync); + if (Opt_extsync) + vmode->extsync = atoboolean(Opt_extsync); + if (Opt_bcast) + vmode->bcast = atoboolean(Opt_bcast); + if (Opt_laced) + vmode->laced = atoboolean(Opt_laced); + if (Opt_double) + vmode->dblscan = atoboolean(Opt_double); + if (Opt_grayscale) + vmode->grayscale = atoboolean(Opt_grayscale); + if (Opt_step) + hstep = vstep = strtoul(Opt_step, NULL, 0); + if (Opt_matchyres) + vmode->vyres = vmode->yres; + if (Opt_move) { + if (!strcasecmp(Opt_move, "left")) { + if (hstep > vmode->left) + Die("The left margin cannot be negative\n"); + vmode->left -= hstep; + vmode->right += hstep; + } else if (!strcasecmp(Opt_move, "right")) { + if (hstep > vmode->right) + Die("The right margin cannot be negative\n"); + vmode->left += hstep; + vmode->right -= hstep; + } else if (!strcasecmp(Opt_move, "up")) { + if (vstep > vmode->upper) + Die("The upper margin cannot be negative\n"); + vmode->upper -= vstep; + vmode->lower += vstep; + } else if (!strcasecmp(Opt_move, "down")) { + if (vstep > vmode->lower) + Die("The lower margin cannot be negative\n"); + vmode->upper += vstep; + vmode->lower -= vstep; + } else + Die("Invalid direction `%s'\n", Opt_move); + } + if (Opt_rgba) { + makeRGBA(vmode, Opt_rgba); + } + if (!FillScanRates(vmode)) + Die("Bad video mode\n"); +} + + + /* + * Display the Video Mode Information + */ + +static void DisplayVModeInfo(struct VideoMode *vmode) +{ + u_int res, sstart, send, total; + + puts(""); + if (!Opt_xfree86) { + printf("mode \"%dx%d", vmode->xres, vmode->yres); + if (vmode->pixclock) { + printf("-%d\"\n", (int)(vmode->vrate+0.5)); + printf(" # D: %5.3f MHz, H: %5.3f kHz, V: %5.3f Hz\n", + vmode->drate/1E6, vmode->hrate/1E3, vmode->vrate); + } else + puts("\""); + printf(" geometry %d %d %d %d %d\n", vmode->xres, vmode->yres, + vmode->vxres, vmode->vyres, vmode->depth); + printf(" timings %d %d %d %d %d %d %d\n", vmode->pixclock, + vmode->left, vmode->right, vmode->upper, vmode->lower, + vmode->hslen, vmode->vslen); + if (vmode->hsync) + puts(" hsync high"); + if (vmode->vsync) + puts(" vsync high"); + if (vmode->csync) + puts(" csync high"); + if (vmode->gsync) + puts(" gsync true"); + if (vmode->extsync) + puts(" extsync true"); + if (vmode->bcast) + puts(" bcast true"); + if (vmode->laced) + puts(" laced true"); + if (vmode->dblscan) + puts(" double true"); + if (vmode->nonstd) + printf(" nonstd %u\n", vmode->nonstd); + if (vmode->accel_flags) + puts(" accel true"); + if (vmode->grayscale) + puts(" grayscale true"); + printf(" rgba %u/%u,%u/%u,%u/%u,%u/%u\n", + vmode->red.length, vmode->red.offset, vmode->green.length, + vmode->green.offset, vmode->blue.length, vmode->blue.offset, + vmode->transp.length, vmode->transp.offset); + puts("endmode\n"); + } else { + printf("Mode \"%dx%d\"\n", vmode->xres, vmode->yres); + if (vmode->pixclock) { + printf(" # D: %5.3f MHz, H: %5.3f kHz, V: %5.3f Hz\n", + vmode->drate/1E6, vmode->hrate/1E3, vmode->vrate); + printf(" DotClock %5.3f\n", vmode->drate/1E6+0.001); + } else + puts(" DotClock Unknown"); + res = vmode->xres; + sstart = res+vmode->right; + send = sstart+vmode->hslen; + total = send+vmode->left; + printf(" HTimings %d %d %d %d\n", res, sstart, send, total); + res = vmode->yres; + sstart = res+vmode->lower; + send = sstart+vmode->vslen; + total = send+vmode->upper; + printf(" VTimings %d %d %d %d\n", res, sstart, send, total); + printf(" Flags "); + if (vmode->laced) + printf(" \"Interlace\""); + if (vmode->dblscan) + printf(" \"DoubleScan\""); + if (vmode->hsync) + printf(" \"+HSync\""); + else + printf(" \"-HSync\""); + if (vmode->vsync) + printf(" \"+VSync\""); + else + printf(" \"-VSync\""); + if (vmode->csync) + printf(" \"Composite\""); + if (vmode->extsync) + puts(" # Warning: XFree86 doesn't support extsync\n"); + if (vmode->bcast) + printf(" \"bcast\""); + if (vmode->accel_flags) + puts(" # Warning: XFree86 doesn't support accel\n"); + if (vmode->grayscale) + puts(" # Warning: XFree86 doesn't support grayscale\n"); + puts("\nEndMode\n"); + } +} + + + /* + * Display the Frame Buffer Device Information + */ + +static void DisplayFBInfo(struct fb_fix_screeninfo *fix) +{ + int i; + + puts("Frame buffer device information:"); + printf(" Name : %s\n", fix->id); + printf(" Address : %p\n", (void *)fix->smem_start); + printf(" Size : %d\n", fix->smem_len); + printf(" Type : "); + switch (fix->type) { + case FB_TYPE_PACKED_PIXELS: + puts("PACKED PIXELS"); + break; + case FB_TYPE_PLANES: + puts("PLANES"); + break; + case FB_TYPE_INTERLEAVED_PLANES: + printf("INTERLEAVED PLANES (%d bytes interleave)\n", + fix->type_aux); + break; + case FB_TYPE_TEXT: + for (i = 0; i < sizeof(Textmodes)/sizeof(*Textmodes); i++) + if (fix->type_aux == Textmodes[i].id) + break; + if (i < sizeof(Textmodes)/sizeof(*Textmodes)) + puts(Textmodes[i].name); + else + printf("Unknown text (%d)\n", fix->type_aux); + break; + case FB_TYPE_VGA_PLANES: + { + struct textentry *t; + + for (t = VGAModes; t->name; t++) + if (fix->type_aux == t->id) + break; + if (t->name) + puts(t->name); + else + printf("Unknown VGA mode (%d)\n", fix->type_aux); + } + break; + default: + printf("%d (UNKNOWN)\n", fix->type); + printf(" Type_aux : %d\n", fix->type_aux); + break; + } + printf(" Visual : "); + switch (fix->visual) { + case FB_VISUAL_MONO01: + puts("MONO01"); + break; + case FB_VISUAL_MONO10: + puts("MONO10"); + break; + case FB_VISUAL_TRUECOLOR: + puts("TRUECOLOR"); + break; + case FB_VISUAL_PSEUDOCOLOR: + puts("PSEUDOCOLOR"); + break; + case FB_VISUAL_DIRECTCOLOR: + puts("DIRECTCOLOR"); + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + puts("STATIC PSEUDOCOLOR"); + break; + default: + printf("%d (UNKNOWN)\n", fix->visual); + break; + } + printf(" XPanStep : %d\n", fix->xpanstep); + printf(" YPanStep : %d\n", fix->ypanstep); + printf(" YWrapStep : %d\n", fix->ywrapstep); + printf(" LineLength : %d\n", fix->line_length); + if (fix->mmio_len) { + printf(" MMIO Address: %p\n", (void *)fix->mmio_start); + printf(" MMIO Size : %d\n", fix->mmio_len); + } + printf(" Accelerator : "); + for (i = 0; i < sizeof(Accelerators)/sizeof(*Accelerators); i++) + if (fix->accel == Accelerators[i].id) + break; + if (i < sizeof(Accelerators)/sizeof(*Accelerators)) + puts(Accelerators[i].name); + else + printf("Unknown (%d)\n", fix->accel); +} + + + /* + * Calculate the Scan Rates for a Video Mode + */ + +static int FillScanRates(struct VideoMode *vmode) +{ + u_int htotal = vmode->left+vmode->xres+vmode->right+vmode->hslen; + u_int vtotal = vmode->upper+vmode->yres+vmode->lower+vmode->vslen; + + if (vmode->dblscan) + vtotal <<= 2; + else if (!vmode->laced) + vtotal <<= 1; + + if (!htotal || !vtotal) + return 0; + + if (vmode->pixclock) { + vmode->drate = 1E12/vmode->pixclock; + vmode->hrate = vmode->drate/htotal; + vmode->vrate = vmode->hrate/vtotal*2; + } else { + vmode->drate = 0; + vmode->hrate = 0; + vmode->vrate = 0; + } + + return 1; +} + + /* + * Print the Usage Template and Exit + */ + +static void Usage(void) +{ + puts(FBSET_VERSION); + printf("\nUsage: %s [options] [mode]\n\n" + "Valid options:\n" + " General options:\n" + " -h, --help : display this usage information\n" + " --test : don't change, just test whether the mode is " + "valid\n" + " -s, --show : display video mode settings\n" + " -i, --info : display all frame buffer information\n" + " -v, --verbose : verbose mode\n" + " -V, --version : print version information\n" + " -x, --xfree86 : XFree86 compatibility mode\n" + " -a, --all : change all virtual consoles on this device\n" + " Frame buffer special device nodes:\n" + " -fb : processed frame buffer device\n" + " (default is " DEFAULT_FRAMEBUFFER ")\n" + " Video mode database:\n" + " -db : video mode database file\n" + " (default is " DEFAULT_MODEDBFILE ")\n" + " Display geometry:\n" + " -xres : horizontal resolution (in pixels)\n" + " -yres : vertical resolution (in pixels)\n" + " -vxres : virtual horizontal resolution (in pixels)\n" + " -vyres : virtual vertical resolution (in pixels)\n" + " -depth : display depth (in bits per pixel)\n" + " -nonstd : select nonstandard video mode\n" + " -g, --geometry ... : set all geometry parameters at once\n" + " -match : set virtual vertical resolution by virtual resolution\n" + " Display timings:\n" + " -pixclock : pixel clock (in picoseconds)\n" + " -left : left margin (in pixels)\n" + " -right : right margin (in pixels)\n" + " -upper : upper margin (in pixel lines)\n" + " -lower : lower margin (in pixel lines)\n" + " -hslen : horizontal sync length (in pixels)\n" + " -vslen : vertical sync length (in pixel lines)\n" + " -t, --timings ... : set all timing parameters at once\n" + " Display flags:\n" + " -accel : hardware text acceleration enable (false or " + "true)\n" + " -hsync : horizontal sync polarity (low or high)\n" + " -vsync : vertical sync polarity (low or high)\n" + " -csync : composite sync polarity (low or high)\n" + " -gsync : synch on green (false or true)\n" + " -extsync : external sync enable (false or true)\n" + " -bcast : broadcast enable (false or true)\n" + " -laced : interlace enable (false or true)\n" + " -double : doublescan enable (false or true)\n" + " -rgba : recommended length of color entries\n" + " -grayscale : grayscale enable (false or true)\n" + " Display positioning:\n" + " -move : move the visible part (left, right, up or " + "down)\n" + " -step : step increment (in pixels or pixel lines)\n" + " (default is 8 horizontal, 2 vertical)\n", + ProgramName); +} + + /* + * Main Routine + */ + +int fbset_main(int argc, char *argv[]) +{ + struct VideoMode *vmode; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int fh = -1, i; + + ProgramName = argv[0]; + + /* + * Parse the Options + */ + + while (--argc > 0) { + argv++; + if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) { + Usage(); + return 1; + } else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--verbose")) + Opt_verbose = 1; + else if (!strcmp(argv[0], "-V") || !strcmp(argv[0], "--version")) + Opt_version = 1; + else if (!strcmp(argv[0], "--test")) + Opt_test = 1; + else if (!strcmp(argv[0], "-s") || !strcmp(argv[0], "--show")) + Opt_show = 1; + else if (!strcmp(argv[0], "-i") || !strcmp(argv[0], "--info")) { + Opt_show = 1; + Opt_info = 1; + } else if (!strcmp(argv[0], "-x") || !strcmp(argv[0], "--xfree86")) + Opt_xfree86 = 1; + else if (!strcmp(argv[0], "-a") || !strcmp(argv[0], "--all")) + Opt_all = 1; + else if (!strcmp(argv[0], "-g") || !strcmp(argv[0], "--geometry")) { + if (argc > 5) { + Opt_xres = argv[1]; + Opt_yres = argv[2]; + Opt_vxres = argv[3]; + Opt_vyres = argv[4]; + Opt_depth = argv[5]; + Opt_change = 1; + argc -= 5; + argv += 5; + } else { + Usage(); + return 1; + } + } else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--timings")) { + if (argc > 7) { + Opt_pixclock = argv[1]; + Opt_left = argv[2]; + Opt_right = argv[3]; + Opt_upper = argv[4]; + Opt_lower = argv[5]; + Opt_hslen = argv[6]; + Opt_vslen = argv[7]; + Opt_change = 1; + argc -= 7; + argv += 7; + } else { + Usage(); + return 1; + } + } else if (!strcmp(argv[0], "-match")) { + Opt_matchyres = argv[0]; + Opt_change = 1; + } else { + for (i = 0; Options[i].name; i++) + if (!strcmp(argv[0], Options[i].name)) + break; + if (Options[i].name) { + if (argc-- > 1) { + *Options[i].value = argv[1]; + Opt_change |= Options[i].change; + argv++; + } else { + Usage(); + return 1; + } + } else if (!Opt_modename) { + Opt_modename = argv[0]; + Opt_change = 1; + } else { + Usage(); + return 1; + } + } + } + + if (Opt_version || Opt_verbose) + puts(FBSET_VERSION); + + if (!Opt_fb) { + Opt_fb = getenv("FRAMEBUFFER"); + if (!Opt_fb) + Opt_fb = DEFAULT_FRAMEBUFFER; + } + + /* + * Open the Frame Buffer Device + */ + + fh = OpenFrameBuffer(Opt_fb); + if (fh < 0) + return 1; + + /* + * Get the Video Mode + */ + + if (Opt_modename) { + +#if 0 + /* + * Read the Video Mode Database + */ + + ReadModeDB(); +#endif + + if (!(vmode = FindVideoMode(Opt_modename))) { + Die("Unknown video mode `%s'\n", Opt_modename); + return 1; + } + Current = *vmode; + if (Opt_verbose) + printf("Using video mode `%s'\n", Opt_modename); + } else { + GetVarScreenInfo(fh, &var); + ConvertToVideoMode(&var, &Current); + if (Opt_verbose) + printf("Using current video mode from `%s'\n", Opt_fb); + } + + if (Opt_change) { + + /* + * Optionally Modify the Video Mode + */ + + ModifyVideoMode(&Current); + + /* + * Set the Video Mode + */ + + ConvertFromVideoMode(&Current, &var); + if (Opt_verbose) + printf("Setting video mode to `%s'\n", Opt_fb); + SetVarScreenInfo(fh, &var); + ConvertToVideoMode(&var, &Current); + } + + /* + * Display some Video Mode Information + */ + + if (Opt_show || !Opt_change) + DisplayVModeInfo(&Current); + + if (Opt_info) { + if (Opt_verbose) + puts("Getting further frame buffer information"); + if (GetFixScreenInfo(fh, &fix) != -1) + DisplayFBInfo(&fix); + } + + /* + * Close the Frame Buffer Device + */ + + CloseFrameBuffer(fh); + + return 0; +} diff --git a/source/fbset_modes_l.l b/source/fbset_modes_l.l new file mode 100644 index 0000000..1ee99c3 --- /dev/null +++ b/source/fbset_modes_l.l @@ -0,0 +1,138 @@ + +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +%{ + +#define YYSTYPE long + +#include +#include + +#define Die Sys_Error + +#include "fbset.h" +#include "fbset_modes_y.h" + +struct keyword { + const char *name; + int token; + int value; +}; + +static struct keyword keywords[] = { + { "mode", MODE, 0 }, + { "geometry", GEOMETRY, 0 }, + { "timings", TIMINGS, 0 }, + { "hsync", HSYNC, 0 }, + { "vsync", VSYNC, 0 }, + { "csync", CSYNC, 0 }, + { "gsync", GSYNC, 0 }, + { "extsync", EXTSYNC, 0 }, + { "bcast", BCAST, 0 }, + { "laced", LACED, 0 }, + { "double", DOUBLE, 0 }, + { "rgba", RGBA, 0 }, + { "nonstd", NONSTD, 0 }, + { "accel", ACCEL, 0 }, + { "grayscale", GRAYSCALE, 0 }, + { "endmode", ENDMODE, 0 }, + { "low", POLARITY, LOW }, + { "high", POLARITY, HIGH }, + { "false", BOOLEAN, FALSE }, + { "true", BOOLEAN, TRUE }, + { "", -1, 0 } +}; + +int line = 1; + + +void yyerror(const char *s) +{ + Die("%s:%d: %s\n", Opt_modedb, line, s); +} + + +int yywrap(void) +{ + return 1; +} + + +static int FindToken(const char *s) +{ + int i; + + for (i = 0; keywords[i].token > 0; i++) + if (!strcasecmp(s, keywords[i].name)) { + yylval = keywords[i].value; + return keywords[i].token; + } + Die("%s:%d: Unknown keyword `%s'\n", Opt_modedb, line, s); +} + + +static const char *CopyString(const char *s) +{ + int len; + char *s2; + + len = strlen(s)-2; + if (!(s2 = malloc(len+1))) + Die("No memory\n"); + strncpy(s2, s+1, len); + s2[len] = '\0'; + return s2; +} + + +%} + +keyword [a-zA-Z][a-zA-Z0-9]* +number [0-9]* +string \"[^\"\n]*\" +comment \#([^\n]*) +space [ \t]+ +junk . + +%% + +{keyword} { + return FindToken(yytext); + } + +{number} { + yylval = strtoul(yytext, NULL, 0); + return NUMBER; + } + +{string} { + yylval = (unsigned long)CopyString(yytext); + return STRING; + } + +{comment}$ break; + +{space} break; + +\n { + line++; + break; + } + +{junk} { + Die("%s:%d: Invalid token `%s'\n", Opt_modedb, line, yytext); + } + +%% diff --git a/source/fbset_modes_y.y b/source/fbset_modes_y.y new file mode 100644 index 0000000..82366f2 --- /dev/null +++ b/source/fbset_modes_y.y @@ -0,0 +1,176 @@ +/* + * Linux Frame Buffer Device Configuration + * + * © Copyright 1995-1998 by Geert Uytterhoeven + * (Geert.Uytterhoeven@cs.kuleuven.ac.be) + * + * -------------------------------------------------------------------------- + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + + +%{ + +#define YYSTYPE long + +#include +#include +#include + +#define Die Sys_Error + +#include "fbset.h" + +extern int yylex(void); +extern void yyerror(const char *s); +extern int line; + + +static struct VideoMode VideoMode; + +static void ClearVideoMode(void) +{ + memset(&VideoMode, 0, sizeof(VideoMode)); + VideoMode.accel_flags = FB_ACCELF_TEXT; +} + +%} + +%start file + +%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC BCAST LACED DOUBLE + RGBA NONSTD ACCEL GRAYSCALE + ENDMODE POLARITY BOOLEAN STRING NUMBER + +%% + +file : vmodes + ; + + +vmodes : /* empty */ + | vmodes vmode + ; + +vmode : MODE STRING geometry timings options ENDMODE + { + VideoMode.name = (char *)$2; + AddVideoMode(&VideoMode); + ClearVideoMode(); + } + ; + +geometry : GEOMETRY NUMBER NUMBER NUMBER NUMBER NUMBER + { + ClearVideoMode(); + VideoMode.xres = $2; + VideoMode.yres = $3; + VideoMode.vxres = $4; + VideoMode.vyres = $5; + VideoMode.depth = $6; + } + ; + +timings : TIMINGS NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER + { + VideoMode.pixclock = $2; + VideoMode.left = $3; + VideoMode.right = $4; + VideoMode.upper = $5; + VideoMode.lower = $6; + VideoMode.hslen = $7; + VideoMode.vslen = $8; + } + ; + +options : /* empty */ + | options hsync + | options vsync + | options csync + | options gsync + | options extsync + | options bcast + | options laced + | options double + | options rgba + | options nonstd + | options accel + | options grayscale + ; + +hsync : HSYNC POLARITY + { + VideoMode.hsync = $2; + } + ; + +vsync : VSYNC POLARITY + { + VideoMode.vsync = $2; + } + ; + +csync : CSYNC POLARITY + { + VideoMode.csync = $2; + } + ; + +gsync : GSYNC POLARITY + { + VideoMode.gsync = $2; + } + ; + +extsync : EXTSYNC BOOLEAN + { + VideoMode.extsync = $2; + } + ; + +bcast : BCAST BOOLEAN + { + VideoMode.bcast = $2; + } + ; + +laced : LACED BOOLEAN + { + VideoMode.laced = $2; + } + ; + +double : DOUBLE BOOLEAN + { + VideoMode.dblscan = $2; + } + ; + +rgba : RGBA STRING + { + makeRGBA(&VideoMode, (const char*)$2); + } + ; + +nonstd : NONSTD NUMBER + { + VideoMode.nonstd = $2; + } + ; + +accel : ACCEL BOOLEAN + { + VideoMode.accel_flags = $2; + } + ; + +grayscale : GRAYSCALE BOOLEAN + { + VideoMode.grayscale = $2; + } + ; + +%% diff --git a/source/in_fbdev.c b/source/in_fbdev.c new file mode 100644 index 0000000..cca5188 --- /dev/null +++ b/source/in_fbdev.c @@ -0,0 +1,154 @@ +/* + in_fbdev.c + + fix this! + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "protocol.h" +#include "cvar.h" +#include "keys.h" + +#include +#include + +cvar_t *_windowed_mouse; + +#include +#include +#include + +int +fd_blocking (int fd, int on) +{ + int x; + +#if defined(_POSIX_SOURCE) || !defined(FIONBIO) +#if !defined(O_NONBLOCK) +# if defined(O_NDELAY) +# define O_NONBLOCK O_NDELAY +# endif +#endif + if ((x = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + if (on) + x &= ~O_NONBLOCK; + else + x |= O_NONBLOCK; + + return fcntl(fd, F_SETFL, x); +#else + x = !on; + + return ioctl(fd, FIONBIO, &x); +#endif +} + +static struct termios old_tty, new_tty; +static int tty_fd = 0; + +void +IN_Init (void) +{ + fd_blocking(0, 0); + tcgetattr(tty_fd, &old_tty); + new_tty = old_tty; + new_tty.c_cc[VMIN] = 1; + new_tty.c_cc[VTIME] = 0; + new_tty.c_lflag &= ~ICANON; + new_tty.c_iflag &= ~IXON; + tcsetattr(tty_fd, TCSADRAIN, &new_tty); +} + +void +IN_Init_Cvars (void) +{ +} + +void +IN_Shutdown (void) +{ +} + +void +IN_SendKeyEvents (void) +{ + int k, down; + char buf[4]; + + if (read(0, buf, 1) == 1) { + k = buf[0]; + switch (k) { + case '\r': + case '\n': + k = K_ENTER; + break; + case '\033': + if (read(0, buf, 2) != 2) + break; + switch (buf[1]) { + case 'A': + k = K_UPARROW; + break; + case 'B': + k = K_DOWNARROW; + break; + case 'C': + k = K_RIGHTARROW; + break; + case 'D': + k = K_LEFTARROW; + break; + } + break; + } + down = 1; + Key_Event(k, -1, down); + Key_Event(k, -1, !down); + } +} + +void +IN_Commands (void) +{ +} + +void +IN_Move (usercmd_t *cmd) +{ +} + +/* +=========== +IN_ModeChanged +=========== +*/ +void +IN_ModeChanged (void) +{ +} diff --git a/source/vid_fbdev.c b/source/vid_fbdev.c new file mode 100644 index 0000000..982d490 --- /dev/null +++ b/source/vid_fbdev.c @@ -0,0 +1,705 @@ +/* + vid_fbdev.c + + Linux FBDev video routines + + based on vid_svgalib.c + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 Nelson Rush. + Copyright (C) 1999-2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999-2000 David Symonds [xoxus@usa.net] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#if defined(HAVE_SYS_IO_H) +# include +#elif defined(HAVE_ASM_IO_H) +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmd.h" +#include "console.h" +#include "cvar.h" +#include "d_local.h" +#include "host.h" +#include "input.h" +#include "qargs.h" +#include "qendian.h" +#include "sys.h" + +#include "fbset.h" + +unsigned short d_8to16table[256]; + +extern void ReadModeDB(void); +extern struct VideoMode *FindVideoMode(const char *name); +void ConvertFromVideoMode(const struct VideoMode *vmode, + struct fb_var_screeninfo *var); +void ConvertToVideoMode(const struct fb_var_screeninfo *var, + struct VideoMode *vmode); + +extern struct VideoMode *VideoModes; +static struct VideoMode current_mode; +static char current_name[32]; +static int num_modes; + +static int fb_fd = -1; +static int tty_fd = 0; + +static byte vid_current_palette[768]; + +static int fbdev_inited = 0; +static int fbdev_backgrounded = 0; +static int UseDisplay = 1; + +static cvar_t *vid_mode; +static cvar_t *vid_redrawfull; +static cvar_t *vid_waitforrefresh; + +static char *framebuffer_ptr; + +static byte backingbuf[48 * 24]; + +void +D_BeginDirectRect (int x, int y, byte * pbitmap, int width, int height) +{ + int i, j, reps, repshift, offset, off; + + if (!fbdev_inited || !vid.direct || fbdev_backgrounded) + return; + + if (vid.aspect > 1.5) { + reps = 2; + repshift = 1; + } else { + reps = 1; + repshift = 0; + } + + for (i = 0; i < (height << repshift); i += reps) { + for (j = 0; j < reps; j++) { + offset = x + ((y << repshift) + i + j) + * vid.rowbytes; + off = offset % 0x10000; + memcpy (&backingbuf[(i + j) * 24], vid.direct + off, width); + memcpy (vid.direct + off, + &pbitmap[(i >> repshift) * width], width); + } + } +} + + +void +D_EndDirectRect (int x, int y, int width, int height) +{ + int i, j, reps, repshift, offset, off; + + if (!fbdev_inited || !vid.direct || fbdev_backgrounded) + return; + + if (vid.aspect > 1.5) { + reps = 2; + repshift = 1; + } else { + reps = 1; + repshift = 0; + } + + for (i = 0; i < (height << repshift); i += reps) { + for (j = 0; j < reps; j++) { + offset = x + ((y << repshift) + i + j) + * vid.rowbytes; + off = offset % 0x10000; + memcpy (vid.direct + off, &backingbuf[(i + j) * 24], width); + } + } +} + + +static void +VID_Gamma_f (void) +{ + float gamma, f, inf; + unsigned char palette[768]; + int i; + + if (Cmd_Argc () == 2) { + gamma = atof (Cmd_Argv (1)); + + for (i = 0; i < 768; i++) { + f = pow ((host_basepal[i] + 1) / 256.0, gamma); + inf = f * 255 + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + palette[i] = inf; + } + + VID_SetPalette (palette); + + /* Force a surface cache flush */ + vid.recalc_refdef = 1; + } +} + + +static void +VID_DescribeMode_f (void) +{ + char *modestr; + struct VideoMode *vmode; + + modestr = Cmd_Argv(1); + vmode = FindVideoMode(modestr); + if (!vmode) { + Con_Printf ("Invalid video mode: %s!\n", modestr); + return; + } + Con_Printf ("%s: %d x %d - %d bpp - %5.3f Hz\n", vmode->name, + vmode->xres, vmode->yres, vmode->depth, vmode->vrate); +} + + +static void +VID_DescribeModes_f (void) +{ + struct VideoMode *vmode; + + for (vmode = VideoModes; vmode; vmode = vmode->next) { + Con_Printf ("%s: %d x %d - %d bpp - %5.3f Hz\n", vmode->name, + vmode->xres, vmode->yres, vmode->depth, vmode->vrate); + } +} + + +/* +================ +VID_NumModes +================ +*/ +static int +VID_NumModes (void) +{ + struct VideoMode *vmode; + int i = 0; + + for (vmode = VideoModes; vmode; vmode = vmode->next) + i++; + + return i; +} + + +static void +VID_NumModes_f (void) +{ + Con_Printf ("%d modes\n", VID_NumModes ()); +} + +int VID_SetMode (char *name, unsigned char *palette); + +extern void fbset_main (int argc, char **argv); + +static void +VID_fbset_f (void) +{ + int i, argc; + char *argv[32]; + + argc = Cmd_Argc(); + if (argc > 32) + argc = 32; + argv[0] = "vid_fbset"; + for (i = 1; i < argc; i++) { + argv[i] = Cmd_Argv(i); + } + fbset_main(argc, argv); +} + +static void +VID_Debug_f (void) +{ + Con_Printf ("mode: %s\n", current_mode.name); + Con_Printf ("height x width: %d x %d\n", current_mode.xres, current_mode.yres); + Con_Printf ("bpp: %d\n", current_mode.depth); + Con_Printf ("vrate: %5.3f\n", current_mode.vrate); + Con_Printf ("vid.aspect: %f\n", vid.aspect); +} + + +static void +VID_InitModes (void) +{ + ReadModeDB(); + num_modes = VID_NumModes(); +} + + +static char * +get_mode (char *name, int width, int height, int depth) +{ + struct VideoMode *vmode; + + for (vmode = VideoModes; vmode; vmode = vmode->next) { + if (name) { + if (!strcmp(vmode->name, name)) + return name; + } else { + if (vmode->xres == width + && vmode->yres == height + && vmode->depth == depth) + return vmode->name; + } + } + + Sys_Printf ("Mode %dx%d (%d bits) not supported\n", + width, height, depth); + + return "640x480-60"; +} + + +void +VID_InitBuffers (void) +{ + int buffersize, zbuffersize, cachesize; + void *vid_surfcache; + + // Calculate the sizes we want first + buffersize = vid.rowbytes * vid.height; + zbuffersize = vid.width * vid.height * sizeof (*d_pzbuffer); + cachesize = D_SurfaceCacheForRes (vid.width, vid.height); + + // Free the old screen buffer + if (vid.buffer) { + free (vid.buffer); + vid.conbuffer = vid.buffer = NULL; + } + // Free the old z-buffer + if (d_pzbuffer) { + free (d_pzbuffer); + d_pzbuffer = NULL; + } + // Free the old surface cache + vid_surfcache = D_SurfaceCacheAddress (); + if (vid_surfcache) { + D_FlushCaches (); + free (vid_surfcache); + vid_surfcache = NULL; + } + // Allocate the new screen buffer + vid.conbuffer = vid.buffer = calloc (buffersize, 1); + if (!vid.conbuffer) { + Sys_Error ("Not enough memory for video mode\n"); + } + // Allocate the new z-buffer + d_pzbuffer = calloc (zbuffersize, 1); + if (!d_pzbuffer) { + free (vid.buffer); + vid.conbuffer = vid.buffer = NULL; + Sys_Error ("Not enough memory for video mode\n"); + } + // Allocate the new surface cache; free the z-buffer if we fail + vid_surfcache = calloc (cachesize, 1); + if (!vid_surfcache) { + free (vid.buffer); + free (d_pzbuffer); + vid.conbuffer = vid.buffer = NULL; + d_pzbuffer = NULL; + Sys_Error ("Not enough memory for video mode\n"); + } + + D_InitCaches (vid_surfcache, cachesize); +} + +static unsigned char *fb_map_addr = 0; +static unsigned long fb_map_length = 0; + +static struct fb_var_screeninfo orig_var; + +void +VID_Shutdown (void) +{ + Sys_Printf ("VID_Shutdown\n"); + + if (!fbdev_inited) + return; + + if (munmap(fb_map_addr, fb_map_length) == -1) { + Sys_Printf("could not unmap framebuffer at %p: %s\n", + fb_map_addr, strerror(errno)); + } else { + if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &orig_var)) + Sys_Printf ("failed to get var screen info\n"); + } + close(fb_fd); + + if (UseDisplay) { + ioctl(tty_fd, KDSETMODE, KD_TEXT); + write(tty_fd, "\033]R", 3); /* reset palette */ + } + + fbdev_inited = 0; +} + + +void +VID_ShiftPalette (unsigned char *p) +{ + VID_SetPalette (p); +} + +static void +loadpalette (unsigned short *red, unsigned short *green, unsigned short *blue) +{ + struct fb_cmap cmap; + + cmap.len = 256; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = NULL; + cmap.start = 0; + if (-1 == ioctl(fb_fd, FBIOPUTCMAP, (void *)&cmap)) + Sys_Error("ioctl FBIOPUTCMAP %s\n", strerror(errno)); +} + +void +VID_SetPalette (byte * palette) +{ + static unsigned short tmppalr[256], tmppalg[256], tmppalb[256]; + unsigned short i, *tpr, *tpg, *tpb; + + if (!fbdev_inited || fbdev_backgrounded || fb_fd < 0) + return; + + memcpy (vid_current_palette, palette, sizeof (vid_current_palette)); + + if (current_mode.depth == 8) { + tpr = tmppalr; + tpg = tmppalg; + tpb = tmppalb; + for (i = 0; i < 256; i++) { + *tpr++ = (*palette++) << 8; + *tpg++ = (*palette++) << 8; + *tpb++ = (*palette++) << 8; + } + + if (UseDisplay) { + loadpalette(tmppalr, tmppalg, tmppalb); + } + } +} + +int +VID_SetMode (char *name, unsigned char *palette) +{ + struct VideoMode *vmode; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int err; + unsigned long smem_start, smem_offset; + + vmode = FindVideoMode(name); + if (!vmode) { + Cvar_Set (vid_mode, current_mode.name); + // Con_Printf ("No such video mode: %s\n", name); + return 0; + } + + current_mode = *vmode; + Cvar_Set (vid_mode, current_mode.name); + strncpy(current_name, current_mode.name, sizeof(current_name)-1); + current_name[31] = 0; + vid.width = vmode->xres; + vid.height = vmode->yres; + vid.rowbytes = vmode->xres * (vmode->depth >> 3); + vid.aspect = ((float) vid.height / (float) vid.width) * (320.0 / 240.0); + vid.colormap = (pixel_t *) host_colormap; + vid.fullbright = 256 - LittleLong (*((int *) vid.colormap + 2048)); + vid.conrowbytes = vid.rowbytes; + vid.conwidth = vid.width; + vid.conheight = vid.height; + vid.numpages = 1; + + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + + if (fb_map_addr) { + if (munmap(fb_map_addr, fb_map_length) == -1) { + Sys_Printf("could not unmap framebuffer at %p: %s\n", + fb_map_addr, strerror(errno)); + } + } + + ConvertFromVideoMode(¤t_mode, &var); + err = ioctl(fb_fd, FBIOPUT_VSCREENINFO, &var); + if (err) + Sys_Error ("Video mode failed: %s\n", name); + ConvertToVideoMode(&var, ¤t_mode); + current_mode.name = current_name; + VID_SetPalette (palette); + + err = ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix); + if (err) + Sys_Error ("Video mode failed: %s\n", name); + smem_start = (unsigned long)fix.smem_start & PAGE_MASK; + smem_offset = (unsigned long)fix.smem_start & ~PAGE_MASK; + fb_map_length = (smem_offset+fix.smem_len+~PAGE_MASK) & PAGE_MASK; + fb_map_addr = (char *)mmap(0, fb_map_length, PROT_WRITE, MAP_SHARED, fb_fd, 0); + if (!fb_map_addr) + Sys_Error ("This mode isn't hapnin'\n"); + vid.direct = framebuffer_ptr = fb_map_addr; + + // alloc screen buffer, z-buffer, and surface cache + VID_InitBuffers (); + + if (!fbdev_inited) { + fbdev_inited = 1; + } + + /* Force a surface cache flush */ + vid.recalc_refdef = 1; + + return 1; +} + +static void +fb_switch_handler (int sig) +{ + if (sig == SIGUSR1) { + fbdev_backgrounded = 1; + } else if (sig == SIGUSR2) { + fbdev_backgrounded = 2; + } +} + +static void +fb_switch_release (void) +{ + ioctl(tty_fd, VT_RELDISP, 1); +} + +static void +fb_switch_acquire (void) +{ + ioctl(tty_fd, VT_RELDISP, VT_ACKACQ); +} + +static void +fb_switch_init (void) +{ + struct sigaction act; + struct vt_mode vtmode; + + memset(&act, 0, sizeof(act)); + act.sa_handler = fb_switch_handler; + sigemptyset(&act.sa_mask); + sigaction(SIGUSR1, &act, 0); + sigaction(SIGUSR2, &act, 0); + + if (ioctl(tty_fd, VT_GETMODE, &vtmode)) { + Sys_Error("ioctl VT_GETMODE: %s\n", strerror(errno)); + } + vtmode.mode = VT_PROCESS; + vtmode.waitv = 0; + vtmode.relsig = SIGUSR1; + vtmode.acqsig = SIGUSR2; + if (ioctl(tty_fd, VT_SETMODE, &vtmode)) { + Sys_Error("ioctl VT_SETMODE: %s\n", strerror(errno)); + } +} + +void +VID_Init (unsigned char *palette) +{ + int w, h, d; + struct VideoMode *vmode; + char *modestr; + char *fbname; + + // plugin_load("in_fbdev.so"); + + if (fbdev_inited) + return; + + Cmd_AddCommand ("gamma", VID_Gamma_f, "No Description"); + + if (UseDisplay) { + fbname = getenv("FRAMEBUFFER"); + if (!fbname) + fbname = "/dev/fb0"; + + fb_fd = open(fbname, O_RDWR); + if (fb_fd < 0) + Sys_Error ("failed to open fb device\n"); + + if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &orig_var)) + Sys_Error ("failed to get var screen info\n"); + + fb_switch_init(); + + VID_InitModes (); + + Cmd_AddCommand ("vid_nummodes", VID_NumModes_f, "No Description"); + Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f, "No Description"); + Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f, "No Description"); + Cmd_AddCommand ("vid_debug", VID_Debug_f, "No Description"); + Cmd_AddCommand ("vid_fbset", VID_fbset_f, "No Description"); + + /* Interpret command-line params */ + w = h = d = 0; + if (getenv ("GFBDEVMODE")) { + modestr = get_mode (getenv ("GFBDEVMODE"), w, h, d); + } else if (COM_CheckParm ("-mode")) { + modestr = get_mode (com_argv[COM_CheckParm ("-mode") + 1], w, h, d); + } else if (COM_CheckParm ("-w") || COM_CheckParm ("-h") + || COM_CheckParm ("-d")) { + if (COM_CheckParm ("-w")) { + w = atoi (com_argv[COM_CheckParm ("-w") + 1]); + } + if (COM_CheckParm ("-h")) { + h = atoi (com_argv[COM_CheckParm ("-h") + 1]); + } + if (COM_CheckParm ("-d")) { + d = atoi (com_argv[COM_CheckParm ("-d") + 1]); + } + modestr = get_mode (0, w, h, d); + } else { + modestr = "640x480-60"; + } + + /* Set vid parameters */ + vmode = FindVideoMode(modestr); + if (!vmode) + Sys_Error("no video mode %s\n", modestr); + current_mode = *vmode; + ioctl(tty_fd, KDSETMODE, KD_GRAPHICS); + VID_SetMode (current_mode.name, palette); + Con_CheckResize (); // Now that we have a window size, fix console + + VID_SetPalette (palette); + } +} + +void +VID_Init_Cvars () +{ + vid_mode = Cvar_Get ("vid_mode", "0", CVAR_NONE, "Sets the video mode"); + vid_redrawfull = Cvar_Get ("vid_redrawfull", "0", CVAR_NONE, + "Redraw entire screen each frame instead of just dirty areas"); + vid_waitforrefresh = Cvar_Get ("vid_waitforrefresh", "0", CVAR_ARCHIVE, + "Wait for vertical retrace before drawing next frame"); +} + + +void +VID_Update (vrect_t *rects) +{ + if (!fbdev_inited) + return; + if (fbdev_backgrounded) { + if (fbdev_backgrounded == 3) { + return; + } else if (fbdev_backgrounded == 2) { + fb_switch_acquire(); + fbdev_backgrounded = 0; + VID_SetPalette(vid_current_palette); + } else if (fbdev_backgrounded == 1) { + fb_switch_release(); + fbdev_backgrounded = 3; + return; + } + } + + if (vid_waitforrefresh->int_val) { + // ??? + } + + if (vid_redrawfull->int_val) { + double *d = (double *)framebuffer_ptr, *s = (double *)vid.buffer; + double *ends = (double *)(vid.buffer + vid.height*vid.rowbytes); + while (s < ends) + *d++ = *s++; + } else { + while (rects) { + int height, width, lineskip, i, j, xoff, yoff; + double *d, *s; + + height = rects->height; + width = rects->width / sizeof(double); + xoff = rects->x; + yoff = rects->y; + lineskip = (vid.width - (xoff + rects->width)) / sizeof(double); + d = (double *)(framebuffer_ptr + yoff * vid.rowbytes + xoff); + s = (double *)(vid.buffer + yoff * vid.rowbytes + xoff); + for (i = yoff; i < height; i++) { + for (j = xoff; j < width; j++) + *d++ = *s++; + d += lineskip; + s += lineskip; + } + rects = rects->pnext; + } + } + + if (current_mode.name && strcmp(vid_mode->string, current_mode.name)) { + VID_SetMode (vid_mode->string, vid_current_palette); + } +} + +void +VID_LockBuffer (void) +{ +} + +void +VID_UnlockBuffer (void) +{ +} + +void +VID_SetCaption (char *text) +{ +}