diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-01-15 08:46:13 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-01-15 08:46:13 +0100 |
commit | 7fe60435bce6595a9c58a9bfd8244d74b5320e96 (patch) | |
tree | 1ac714a916e02fc90901ddac8bc2a3c6d051d28c /Source/DirectFB/systems/fbdev | |
download | directfb-voodoo-7fe60435bce6595a9c58a9bfd8244d74b5320e96.tar.gz directfb-voodoo-7fe60435bce6595a9c58a9bfd8244d74b5320e96.tar.bz2 directfb-voodoo-7fe60435bce6595a9c58a9bfd8244d74b5320e96.zip |
Import DirectFB141_2k11R3_beta5
Diffstat (limited to 'Source/DirectFB/systems/fbdev')
-rwxr-xr-x | Source/DirectFB/systems/fbdev/Makefile.am | 48 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/Makefile.in | 637 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/agp.c | 511 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/agp.h | 53 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/fb.h | 366 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/fbdev.c | 2782 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/fbdev.h | 142 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/fbdev_surface_pool.c | 423 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/surfacemanager.c | 617 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/surfacemanager.h | 117 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/vt.c | 675 | ||||
-rwxr-xr-x | Source/DirectFB/systems/fbdev/vt.h | 83 |
12 files changed, 6454 insertions, 0 deletions
diff --git a/Source/DirectFB/systems/fbdev/Makefile.am b/Source/DirectFB/systems/fbdev/Makefile.am new file mode 100755 index 0000000..9aa25b4 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/Makefile.am @@ -0,0 +1,48 @@ +## Makefile.am for DirectFB/systems/fbdev + +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src + +AM_CPPFLAGS = -D_XOPEN_SOURCE=500 + + +internalincludedir = $(INTERNALINCLUDEDIR)/fbdev + +internalinclude_HEADERS = \ + agp.h \ + fb.h \ + fbdev.h \ + surfacemanager.h \ + vt.h + + +systemsdir = $(MODULEDIR)/systems + +if BUILD_STATIC +systems_DATA = libdirectfb_fbdev.o +endif +systems_LTLIBRARIES = libdirectfb_fbdev.la + +libdirectfb_fbdev_la_LDFLAGS = \ + -avoid-version \ + -module \ + $(SYSFS_LIBS) + +libdirectfb_fbdev_la_SOURCES = \ + agp.c \ + fbdev.c \ + fbdev_surface_pool.c \ + surfacemanager.c \ + vt.c + +libdirectfb_fbdev_la_LIBADD = \ + $(top_builddir)/lib/direct/libdirect.la \ + $(top_builddir)/lib/fusion/libfusion.la \ + $(top_builddir)/src/libdirectfb.la + + +include $(top_srcdir)/rules/libobject.make diff --git a/Source/DirectFB/systems/fbdev/Makefile.in b/Source/DirectFB/systems/fbdev/Makefile.in new file mode 100755 index 0000000..ddf7e26 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/Makefile.in @@ -0,0 +1,637 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +DIST_COMMON = $(internalinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/rules/libobject.make +subdir = systems/fbdev +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(systemsdir)" "$(DESTDIR)$(systemsdir)" \ + "$(DESTDIR)$(internalincludedir)" +systemsLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(systems_LTLIBRARIES) +libdirectfb_fbdev_la_DEPENDENCIES = \ + $(top_builddir)/lib/direct/libdirect.la \ + $(top_builddir)/lib/fusion/libfusion.la \ + $(top_builddir)/src/libdirectfb.la +am_libdirectfb_fbdev_la_OBJECTS = agp.lo fbdev.lo \ + fbdev_surface_pool.lo surfacemanager.lo vt.lo +libdirectfb_fbdev_la_OBJECTS = $(am_libdirectfb_fbdev_la_OBJECTS) +libdirectfb_fbdev_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libdirectfb_fbdev_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libdirectfb_fbdev_la_SOURCES) +DIST_SOURCES = $(libdirectfb_fbdev_la_SOURCES) +systemsDATA_INSTALL = $(INSTALL_DATA) +DATA = $(systems_DATA) +internalincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(internalinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +ASFLAGS = @ASFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIR = @DATADIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DFB_CFLAGS_OMIT_FRAME_POINTER = @DFB_CFLAGS_OMIT_FRAME_POINTER@ +DFB_INTERNAL_CFLAGS = @DFB_INTERNAL_CFLAGS@ +DFB_LDFLAGS = @DFB_LDFLAGS@ +DFB_SMOOTH_SCALING = @DFB_SMOOTH_SCALING@ +DIRECTFB_BINARY_AGE = @DIRECTFB_BINARY_AGE@ +DIRECTFB_CSOURCE = @DIRECTFB_CSOURCE@ +DIRECTFB_INTERFACE_AGE = @DIRECTFB_INTERFACE_AGE@ +DIRECTFB_MAJOR_VERSION = @DIRECTFB_MAJOR_VERSION@ +DIRECTFB_MICRO_VERSION = @DIRECTFB_MICRO_VERSION@ +DIRECTFB_MINOR_VERSION = @DIRECTFB_MINOR_VERSION@ +DIRECTFB_VERSION = @DIRECTFB_VERSION@ +DIRECT_BUILD_DEBUG = @DIRECT_BUILD_DEBUG@ +DIRECT_BUILD_DEBUGS = @DIRECT_BUILD_DEBUGS@ +DIRECT_BUILD_GETTID = @DIRECT_BUILD_GETTID@ +DIRECT_BUILD_NETWORK = @DIRECT_BUILD_NETWORK@ +DIRECT_BUILD_STDBOOL = @DIRECT_BUILD_STDBOOL@ +DIRECT_BUILD_TEXT = @DIRECT_BUILD_TEXT@ +DIRECT_BUILD_TRACE = @DIRECT_BUILD_TRACE@ +DSYMUTIL = @DSYMUTIL@ +DYNLIB = @DYNLIB@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +FREETYPE_PROVIDER = @FREETYPE_PROVIDER@ +FUSION_BUILD_KERNEL = @FUSION_BUILD_KERNEL@ +FUSION_BUILD_MULTI = @FUSION_BUILD_MULTI@ +FUSION_MESSAGE_SIZE = @FUSION_MESSAGE_SIZE@ +GIF_PROVIDER = @GIF_PROVIDER@ +GREP = @GREP@ +HAVE_LINUX = @HAVE_LINUX@ +INCLUDEDIR = @INCLUDEDIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTERNALINCLUDEDIR = @INTERNALINCLUDEDIR@ +JPEG_PROVIDER = @JPEG_PROVIDER@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBJPEG = @LIBJPEG@ +LIBOBJS = @LIBOBJS@ +LIBPNG = @LIBPNG@ +LIBPNG_CONFIG = @LIBPNG_CONFIG@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_BINARY = @LT_BINARY@ +LT_CURRENT = @LT_CURRENT@ +LT_RELEASE = @LT_RELEASE@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAN2HTML = @MAN2HTML@ +MKDIR_P = @MKDIR_P@ +MODULEDIR = @MODULEDIR@ +MODULEDIRNAME = @MODULEDIRNAME@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OSX_LIBS = @OSX_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PNG_PROVIDER = @PNG_PROVIDER@ +RANLIB = @RANLIB@ +RUNTIME_SYSROOT = @RUNTIME_SYSROOT@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_LIBS = @SDL_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOPATH = @SOPATH@ +STRIP = @STRIP@ +SYSCONFDIR = @SYSCONFDIR@ +SYSFS_LIBS = @SYSFS_LIBS@ +THREADFLAGS = @THREADFLAGS@ +THREADLIB = @THREADLIB@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_LIBS = @TSLIB_LIBS@ +VERSION = @VERSION@ +VNC_CFLAGS = @VNC_CFLAGS@ +VNC_CONFIG = @VNC_CONFIG@ +VNC_LIBS = @VNC_LIBS@ +X11_CFLAGS = @X11_CFLAGS@ +X11_LIBS = @X11_LIBS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src + +AM_CPPFLAGS = -D_XOPEN_SOURCE=500 +internalincludedir = $(INTERNALINCLUDEDIR)/fbdev +internalinclude_HEADERS = \ + agp.h \ + fb.h \ + fbdev.h \ + surfacemanager.h \ + vt.h + +systemsdir = $(MODULEDIR)/systems +@BUILD_STATIC_TRUE@systems_DATA = libdirectfb_fbdev.o +systems_LTLIBRARIES = libdirectfb_fbdev.la +libdirectfb_fbdev_la_LDFLAGS = \ + -avoid-version \ + -module \ + $(SYSFS_LIBS) + +libdirectfb_fbdev_la_SOURCES = \ + agp.c \ + fbdev.c \ + fbdev_surface_pool.c \ + surfacemanager.c \ + vt.c + +libdirectfb_fbdev_la_LIBADD = \ + $(top_builddir)/lib/direct/libdirect.la \ + $(top_builddir)/lib/fusion/libfusion.la \ + $(top_builddir)/src/libdirectfb.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/rules/libobject.make $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu systems/fbdev/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu systems/fbdev/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-systemsLTLIBRARIES: $(systems_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(systemsdir)" || $(MKDIR_P) "$(DESTDIR)$(systemsdir)" + @list='$(systems_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(systemsLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(systemsdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(systemsLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(systemsdir)/$$f"; \ + else :; fi; \ + done + +uninstall-systemsLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(systems_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(systemsdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(systemsdir)/$$p"; \ + done + +clean-systemsLTLIBRARIES: + -test -z "$(systems_LTLIBRARIES)" || rm -f $(systems_LTLIBRARIES) + @list='$(systems_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdirectfb_fbdev.la: $(libdirectfb_fbdev_la_OBJECTS) $(libdirectfb_fbdev_la_DEPENDENCIES) + $(libdirectfb_fbdev_la_LINK) -rpath $(systemsdir) $(libdirectfb_fbdev_la_OBJECTS) $(libdirectfb_fbdev_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fbdev.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fbdev_surface_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surfacemanager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vt.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-systemsDATA: $(systems_DATA) + @$(NORMAL_INSTALL) + test -z "$(systemsdir)" || $(MKDIR_P) "$(DESTDIR)$(systemsdir)" + @list='$(systems_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(systemsDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(systemsdir)/$$f'"; \ + $(systemsDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(systemsdir)/$$f"; \ + done + +uninstall-systemsDATA: + @$(NORMAL_UNINSTALL) + @list='$(systems_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(systemsdir)/$$f'"; \ + rm -f "$(DESTDIR)$(systemsdir)/$$f"; \ + done +install-internalincludeHEADERS: $(internalinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(internalincludedir)" || $(MKDIR_P) "$(DESTDIR)$(internalincludedir)" + @list='$(internalinclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(internalincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(internalincludedir)/$$f'"; \ + $(internalincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(internalincludedir)/$$f"; \ + done + +uninstall-internalincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(internalinclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(internalincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(internalincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(systemsdir)" "$(DESTDIR)$(systemsdir)" "$(DESTDIR)$(internalincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-systemsLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-internalincludeHEADERS install-systemsDATA \ + install-systemsLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-internalincludeHEADERS uninstall-systemsDATA \ + uninstall-systemsLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-systemsLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-internalincludeHEADERS install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + install-systemsDATA install-systemsLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-internalincludeHEADERS \ + uninstall-systemsDATA uninstall-systemsLTLIBRARIES + +%.o: .libs/%.a %.la + rm -f $<.tmp/*.o + if test -d $<.tmp; then rmdir $<.tmp; fi + mkdir $<.tmp + (cd $<.tmp && $(AR) x ../../$<) + $(LD) -o $@ -r $<.tmp/*.o + rm -f $<.tmp/*.o && rmdir $<.tmp + +.PHONY: $(LTLIBRARIES:%.la=.libs/%.a) +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Source/DirectFB/systems/fbdev/agp.c b/Source/DirectFB/systems/fbdev/agp.c new file mode 100755 index 0000000..286d4db --- /dev/null +++ b/Source/DirectFB/systems/fbdev/agp.c @@ -0,0 +1,511 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <errno.h> + +#include <asm/types.h> /* Needs to be included before dfb_types.h */ + +#include <directfb.h> + +#include <direct/mem.h> +#include <direct/messages.h> +#include <direct/util.h> + +#include <fusion/fusion.h> +#include <fusion/shmalloc.h> + +#include <core/core.h> +#include <core/coredefs.h> +#include <core/coretypes.h> + +#include <misc/conf.h> + +#include "fbdev.h" +#include "agp.h" + +#define PAGE_SIZE direct_pagesize() + +/*****************************************************************************/ + +extern FBDev *dfb_fbdev; + +static AGPDevice *dfb_agp = NULL; + +/*****************************************************************************/ + +static DFBResult +dfb_agp_info( agp_info *info ) +{ + D_ASSERT( info != NULL ); + + if (ioctl( dfb_agp->fd, AGPIOC_INFO, info )) { + D_PERROR( "DirectFB/FBDev/agp: Could not get AGP info!\n" ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_setup( u32 mode ) +{ + agp_setup setup; + + setup.agp_mode = mode; + + if (ioctl( dfb_agp->fd, AGPIOC_SETUP, &setup )) { + D_PERROR( "DirectFB/FBDev/agp: AGP setup failed!\n" ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_acquire( void ) +{ + if (ioctl( dfb_agp->fd, AGPIOC_ACQUIRE, 0 )) { + D_PERROR( "DirectFB/FBDev/agp: Acquire failed!\n" ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_release( void ) +{ + if (ioctl( dfb_agp->fd, AGPIOC_RELEASE, 0 )) { + D_PERROR( "DirectFB/FBDev/agp: Release failed!\n" ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_allocate( unsigned long size, int *key ) +{ + agp_allocate alloc; + int pages; + + D_ASSERT( key != NULL ); + + pages = size / PAGE_SIZE; + if (pages % PAGE_SIZE) + pages++; + + if (pages == 0) { + D_BUG( "attempted to allocate 0 pages!"); + return DFB_BUG; + } + + alloc.pg_count = pages; + alloc.type = 0; + + if (ioctl( dfb_agp->fd, AGPIOC_ALLOCATE, &alloc )) { + D_PERROR( "DirectFB/FBDev/agp: " + "Could not allocate %d pages!\n", pages ); + return errno2result( errno ); + } + + *key = alloc.key; + + return DFB_OK; +} + +static DFBResult +dfb_agp_deallocate( int key ) +{ + if (ioctl( dfb_agp->fd, AGPIOC_DEALLOCATE, key )) { + D_PERROR( "DirectFB/FBDev/agp: " + "Deallocate failed (key = %d)!\n", key ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_bind( unsigned int offset, int key ) +{ + agp_bind bind; + + if (offset % PAGE_SIZE) { + D_BUG( "offset is not page-aligned!" ); + return DFB_BUG; + } + + bind.pg_start = offset / PAGE_SIZE; + bind.key = key; + + if (ioctl( dfb_agp->fd, AGPIOC_BIND, &bind )) { + D_PERROR( "DirectFB/FBDev/agp: " + "Bind failed (key = %d, offset = 0x%x)!\n", + key, offset ); + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_agp_unbind( int key ) +{ + agp_unbind unbind; + + unbind.priority = 0; + unbind.key = key; + + if (ioctl( dfb_agp->fd, AGPIOC_UNBIND, &unbind )) { + D_PERROR( "DirectFB/FBDev/agp: " + "Unbind failed (key = %d)!\n", + key ); + return errno2result( errno ); + } + + return DFB_OK; +} + +/*****************************************************************************/ + +static inline u16 +pci_read_word( int fd, int pos ) +{ + u8 b[2]; + + if (pread( fd, b, 2, pos ) < 2) + return 0; + + return b[0] | (b[1] << 8); +} + +static inline u8 +pci_read_byte( int fd, int pos ) +{ + u8 b; + + if (pread( fd, &b, 1, pos ) < 1) + return 0; + + return b; +} + +#define PCI_STATUS 0x06 +#define PCI_STATUS_CAP_LIST 0x10 +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_AGP 0x02 + +static bool +dfb_agp_capable( int bus, int dev, int func ) +{ + bool found = false; + char path[22]; + int fd; + + /* XXX: the following detection method requires suid root */ + + snprintf( path, sizeof(path), + "/proc/bus/pci/%02x/%02x.%01x", bus, dev, func ); + + fd = open( path, O_RDONLY | O_SYNC ); + if (fd < 0) { + D_PERROR( "DirectFB/FBDev/agp: " + "Couldn't open '%s'!\n", path ); + return false; + } + + /* stolen from linux/drivers/pci/pci.c */ + if (pci_read_word( fd, PCI_STATUS ) & PCI_STATUS_CAP_LIST) { + int pos, id; + int ttl = 48; + + pos = pci_read_byte( fd, PCI_CAPABILITY_LIST ); + while (ttl-- && pos >= 0x40) { + pos &= ~3; + + id = pci_read_byte( fd, pos ); + if (id == 0xff) + break; + if (id == PCI_CAP_ID_AGP) { + found = true; + break; + } + + pos = pci_read_byte( fd, pos+1 ); + } + } + + close( fd ); + + return found; +} + +/*****************************************************************************/ + +DFBResult +dfb_agp_initialize( void ) +{ + AGPShared *shared; + unsigned int agp_avail; + DFBResult ret = DFB_FAILURE; + + if (dfb_agp) { + D_BUG( "dfb_agp_initialize() already called!" ); + return DFB_BUG; + } + + /* Precheck for AGP capable device. */ + if (!dfb_agp_capable( dfb_fbdev->shared->pci.bus, + dfb_fbdev->shared->pci.dev, + dfb_fbdev->shared->pci.func )) + return DFB_UNSUPPORTED; + + dfb_agp = D_CALLOC( 1, sizeof(AGPDevice) ); + if (!dfb_agp) + return D_OOM(); + + shared = SHCALLOC( dfb_fbdev->shared->shmpool, 1, sizeof(AGPShared) ); + if (!shared) { + D_ERROR( "DirectFB/FBDev/agp: Could not allocate shared memory!\n" ); + ret = DFB_NOSHAREDMEMORY; + goto error0; + } + + dfb_agp->fd = direct_try_open( "/dev/agpgart", + "/dev/misc/agpgart", O_RDWR, true ); + if (dfb_agp->fd < 0) { + ret = errno2result( errno ); + D_ERROR( "DirectFB/FBDev/agp: Error opening AGP device!\n" ); + goto error1; + } + + ret = dfb_agp_acquire(); + if (ret) + goto error2; + + ret = dfb_agp_info( &shared->info ); + if (ret) + goto error2; + + D_DEBUG( "DirectFB/FBDev/agp: " + "Bridge supports: AGP%s%s%s%s%s%s\n", + shared->info.agp_mode & 0x001 ? " 1X" : "", + shared->info.agp_mode & 0x002 ? " 2X" : "", + shared->info.agp_mode & 0x004 ? " 4X" : "", + shared->info.agp_mode & 0x008 ? " 8X" : "", + shared->info.agp_mode & 0x200 ? ", SBA" : "", + shared->info.agp_mode & 0x010 ? ", FW" : "" ); + + shared->info.agp_mode &= ~0xf; + shared->info.agp_mode |= dfb_config->agp; + shared->info.agp_mode |= dfb_config->agp - 1; + + ret = dfb_agp_setup( shared->info.agp_mode ); + if (ret) + goto error2; + dfb_agp_info( &shared->info ); + + D_DEBUG( "DirectFB/FBDev/agp: " + "AGP aperture at 0x%x (%zu MB)\n", + (unsigned int)shared->info.aper_base, shared->info.aper_size ); + + agp_avail = (shared->info.pg_total - shared->info.pg_used) * PAGE_SIZE; + if (agp_avail == 0) { + D_ERROR( "DirectFB/FBDev/agp: No AGP memory available!\n" ); + ret = DFB_INIT; + goto error2; + } + + shared->agp_mem = shared->info.aper_size << 20; + if (shared->agp_mem > agp_avail) + shared->agp_mem = agp_avail; + + ret = dfb_agp_allocate( shared->agp_mem, &shared->agp_key ); + if (ret) + goto error3; + + ret = dfb_agp_bind( shared->agp_key, 0 ); + if (ret) + goto error4; + + dfb_agp->base = mmap( NULL, shared->info.aper_size << 20, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_agp->fd, 0 ); + if (dfb_agp->base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev/agp: Could not mmap the AGP aperture!\n" ); + ret = DFB_INIT; + goto error5; + } + + dfb_agp_release(); + + dfb_fbdev->agp = dfb_agp; + dfb_fbdev->shared->agp = shared; + + return DFB_OK; + +error5: + dfb_agp_unbind( shared->agp_key ); +error4: + dfb_agp_deallocate( shared->agp_key ); +error3: + dfb_agp_release(); +error2: + close( dfb_agp->fd ); +error1: + SHFREE( dfb_fbdev->shared->shmpool, shared ); +error0: + D_FREE( dfb_agp ); + dfb_agp = NULL; + + return ret; +} + +DFBResult +dfb_agp_join( void ) +{ + AGPShared *shared; + DFBResult ret = DFB_FAILURE; + + if (dfb_agp) { + D_BUG( "dfb_agp_join() already called!" ); + return DFB_BUG; + } + + shared = dfb_fbdev->shared->agp; + if (!shared) + return DFB_OK; + + dfb_agp = D_CALLOC( 1, sizeof(AGPDevice) ); + if (!dfb_agp) + return D_OOM(); + + dfb_agp->fd = direct_try_open( "/dev/agpgart", + "/dev/misc/agpgart", O_RDWR, true ); + if (dfb_agp->fd < 0) { + ret = errno2result( errno ); + D_ERROR( "DirectFB/FBDev/agp: Error opening AGP device!\n" ); + goto error0; + } + + ret = dfb_agp_acquire(); + if (ret) + goto error1; + + dfb_agp->base = mmap( NULL, shared->info.aper_size << 20, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_agp->fd, 0 ); + if (dfb_agp->base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev/agp: Could not mmap the AGP aperture!\n" ); + ret = DFB_INIT; + goto error2; + } + + D_DEBUG( "DirectFB/FBDev/agp: AGP aperture mapped at %p\n", dfb_agp->base ); + + dfb_agp_release(); + + dfb_fbdev->agp = dfb_agp; + + return DFB_OK; + +error2: + dfb_agp_release(); +error1: + close( dfb_agp->fd ); +error0: + D_FREE( dfb_agp ); + dfb_agp = NULL; + + return ret; +} + +DFBResult +dfb_agp_shutdown( void ) +{ + AGPShared *shared; + + if (!dfb_agp) + return DFB_INVARG; + + shared = dfb_fbdev->shared->agp; + + dfb_agp_acquire(); + + munmap( dfb_agp->base, shared->info.aper_size << 20 ); + + dfb_agp_unbind( shared->agp_key ); + dfb_agp_deallocate( shared->agp_key ); + + dfb_agp_release(); + close( dfb_agp->fd ); + + SHFREE( dfb_fbdev->shared->shmpool, shared ); + D_FREE( dfb_agp ); + + dfb_fbdev->shared->agp = NULL; + dfb_fbdev->agp = dfb_agp = NULL; + + return DFB_OK; +} + +DFBResult +dfb_agp_leave( void ) +{ + AGPShared *shared; + + if (!dfb_agp) + return DFB_INVARG; + + shared = dfb_fbdev->shared->agp; + + dfb_agp_acquire(); + + munmap( dfb_agp->base, shared->info.aper_size << 20 ); + + dfb_agp_release(); + + close( dfb_agp->fd ); + D_FREE( dfb_agp ); + + dfb_fbdev->agp = dfb_agp = NULL; + + return DFB_OK; +} + diff --git a/Source/DirectFB/systems/fbdev/agp.h b/Source/DirectFB/systems/fbdev/agp.h new file mode 100755 index 0000000..44313a3 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/agp.h @@ -0,0 +1,53 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __AGP_H__ +#define __AGP_H__ + +#include <linux/agpgart.h> + +typedef struct { + unsigned int agp_mem; + int agp_key; + agp_info info; +} AGPShared; + +typedef struct { + int fd; + void *base; +} AGPDevice; + + +DFBResult dfb_agp_initialize( void ); +DFBResult dfb_agp_shutdown( void ); + +DFBResult dfb_agp_join( void ); +DFBResult dfb_agp_leave( void ); + +#endif /* __AGP_H__ */ + diff --git a/Source/DirectFB/systems/fbdev/fb.h b/Source/DirectFB/systems/fbdev/fb.h new file mode 100755 index 0000000..6cc1399 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/fb.h @@ -0,0 +1,366 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include <dfb_types.h> + +/* Definitions of frame buffers */ + +#define FB_MAJOR 29 +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 + + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ +#define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_NV_10 43 /* nVidia Arch 10 */ +#define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ +#define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ +#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ +#define FB_ACCEL_EP9X 99 /* CirrusLogic EP9X family */ + +#define FB_ACCEL_SAVAGE4 0x80 /* S3 Savage4 */ +#define FB_ACCEL_SAVAGE3D 0x81 /* S3 Savage3D */ +#define FB_ACCEL_SAVAGE3D_MV 0x82 /* S3 Savage3D-MV */ +#define FB_ACCEL_SAVAGE2000 0x83 /* S3 Savage2000 */ +#define FB_ACCEL_SAVAGE_MX_MV 0x84 /* S3 Savage/MX-MV */ +#define FB_ACCEL_SAVAGE_MX 0x85 /* S3 Savage/MX */ +#define FB_ACCEL_SAVAGE_IX_MV 0x86 /* S3 Savage/IX-MV */ +#define FB_ACCEL_SAVAGE_IX 0x87 /* S3 Savage/IX */ +#define FB_ACCEL_PROSAVAGE_PM 0x88 /* S3 ProSavage PM133 */ +#define FB_ACCEL_PROSAVAGE_KM 0x89 /* S3 ProSavage KM133 */ +#define FB_ACCEL_S3TWISTER_P 0x8a /* S3 Twister */ +#define FB_ACCEL_S3TWISTER_K 0x8b /* S3 TwisterK */ +#define FB_ACCEL_SUPERSAVAGE 0x8c /* S3 Supersavage */ +#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ +#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + u32 smem_len; /* Length of frame buffer mem */ + u32 type; /* see FB_TYPE_* */ + u32 type_aux; /* Interleave for interleaved Planes */ + u32 visual; /* see FB_VISUAL_* */ + u16 xpanstep; /* zero if no hardware panning */ + u16 ypanstep; /* zero if no hardware panning */ + u16 ywrapstep; /* zero if no hardware ywrap */ + u32 line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + u32 mmio_len; /* Length of Memory Mapped I/O */ + u32 accel; /* Indicate to driver which */ + /* specific chip/card we have */ + u16 reserved[3]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ +struct fb_bitfield { + u32 offset; /* beginning of bitfield */ + u32 length; /* length of bitfield */ + u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +/* + * Display rotation support + */ +#define FB_ROTATE_UR 0 +#define FB_ROTATE_CW 1 +#define FB_ROTATE_UD 2 +#define FB_ROTATE_CCW 3 + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + u32 xres; /* visible resolution */ + u32 yres; + u32 xres_virtual; /* virtual resolution */ + u32 yres_virtual; + u32 xoffset; /* offset from virtual to visible */ + u32 yoffset; /* resolution */ + + u32 bits_per_pixel; /* guess what */ + u32 grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + u32 nonstd; /* != 0 Non standard pixel format */ + + u32 activate; /* see FB_ACTIVATE_* */ + + u32 height; /* height of picture in mm */ + u32 width; /* width of picture in mm */ + + u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + u32 pixclock; /* pixel clock in ps (pico seconds) */ + u32 left_margin; /* time from sync to picture */ + u32 right_margin; /* time from picture to sync */ + u32 upper_margin; /* time from sync to picture */ + u32 lower_margin; + u32 hsync_len; /* length of horizontal sync */ + u32 vsync_len; /* length of vertical sync */ + u32 sync; /* see FB_SYNC_* */ + u32 vmode; /* see FB_VMODE_* */ + u32 rotate; /* angle we rotate counter clockwise */ + u32 reserved[5]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + u32 start; /* First entry */ + u32 len; /* Number of entries */ + u16 *red; /* Red values */ + u16 *green; + u16 *blue; + u16 *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + u32 console; + u32 framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + u32 flags; /* FB_VBLANK flags */ + u32 count; /* counter of retraces since boot */ + u32 vcount; /* current scanline position */ + u32 hcount; /* current scandot position */ + u32 reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + u32 dx; + u32 dy; + u32 width; + u32 height; + u32 sx; + u32 sy; +}; + +struct fb_fillrect { + u32 dx; /* screen-relative */ + u32 dy; + u32 width; + u32 height; + u32 color; + u32 rop; +}; + +struct fb_image { + u32 dx; /* Where to place image */ + u32 dy; + u32 width; /* Size of image */ + u32 height; + u32 fg_color; /* Only used when a mono bitmap */ + u32 bg_color; + u8 depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETIMAGE 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + u16 x, y; +}; + +struct fb_cursor { + u16 set; /* what to set */ + u16 enable; /* cursor on/off */ + u16 rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +#endif /* _LINUX_FB_H */ diff --git a/Source/DirectFB/systems/fbdev/fbdev.c b/Source/DirectFB/systems/fbdev/fbdev.c new file mode 100755 index 0000000..3691cff --- /dev/null +++ b/Source/DirectFB/systems/fbdev/fbdev.c @@ -0,0 +1,2782 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <config.h> + +#include <asm/types.h> /* Needs to be included before dfb_types.h */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#if defined(HAVE_SYSIO) +# include <sys/io.h> +#endif +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/kd.h> + +#include <pthread.h> + +#ifdef USE_SYSFS +# include <sysfs/libsysfs.h> +#endif + +#include <fusion/arena.h> +#include <fusion/fusion.h> +#include <fusion/reactor.h> +#include <fusion/shmalloc.h> + +#include <directfb.h> + +#include <core/core.h> +#include <core/coredefs.h> +#include <core/coretypes.h> + +#include <core/layer_control.h> +#include <core/layers.h> +#include <core/gfxcard.h> +#include <core/palette.h> +#include <core/screen.h> +#include <core/screens.h> +#include <core/surface.h> +#include <core/surface_buffer.h> +#include <core/surface_pool.h> +#include <core/state.h> +#include <core/windows.h> + +#include <gfx/convert.h> + +#include <direct/mem.h> +#include <direct/memcpy.h> +#include <direct/messages.h> +#include <direct/signals.h> +#include <direct/system.h> +#include <direct/util.h> + +#include <misc/conf.h> +#include <misc/util.h> + +#include "fbdev.h" +#include "fb.h" +#include "vt.h" +#include "agp.h" + +#include <core/core_system.h> + +DFB_CORE_SYSTEM( fbdev ) + + +D_DEBUG_DOMAIN( FBDev_Mode, "FBDev/Mode", "FBDev System Module Mode Switching" ); + +/******************************************************************************/ + +extern const SurfacePoolFuncs fbdevSurfacePoolFuncs; + +static FusionCallHandlerResult +fbdev_ioctl_call_handler( int caller, + int call_arg, + void *call_ptr, + void *ctx, + unsigned int serial, + int *ret_val ); + +static int fbdev_ioctl( int request, void *arg, int arg_size ); + +#define FBDEV_IOCTL(request,arg) fbdev_ioctl( request, arg, sizeof(*(arg)) ) + +FBDev *dfb_fbdev = NULL; + +/******************************************************************************/ + +static int primaryLayerDataSize ( void ); + +static int primaryRegionDataSize( void ); + +static DFBResult primaryInitLayer ( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ); + +static DFBResult primarySetColorAdjustment( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adjustment ); + +static DFBResult primaryTestRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ); + +static DFBResult primaryAddRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config ); + +static DFBResult primarySetRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock ); + +static DFBResult primaryRemoveRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ); + +static DFBResult primaryFlipRegion ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ); + + +static DisplayLayerFuncs primaryLayerFuncs = { + .LayerDataSize = primaryLayerDataSize, + .RegionDataSize = primaryRegionDataSize, + .InitLayer = primaryInitLayer, + + .SetColorAdjustment = primarySetColorAdjustment, + + .TestRegion = primaryTestRegion, + .AddRegion = primaryAddRegion, + .SetRegion = primarySetRegion, + .RemoveRegion = primaryRemoveRegion, + .FlipRegion = primaryFlipRegion, +}; + +/******************************************************************************/ + +static DFBResult primaryInitScreen ( CoreScreen *screen, + CoreGraphicsDevice *device, + void *driver_data, + void *screen_data, + DFBScreenDescription *description ); + +static DFBResult primarySetPowerMode( CoreScreen *screen, + void *driver_data, + void *screen_data, + DFBScreenPowerMode mode ); + +static DFBResult primaryWaitVSync ( CoreScreen *screen, + void *driver_data, + void *layer_data ); + +static DFBResult primaryGetScreenSize( CoreScreen *screen, + void *driver_data, + void *screen_data, + int *ret_width, + int *ret_height ); + +static ScreenFuncs primaryScreenFuncs = { + .InitScreen = primaryInitScreen, + .SetPowerMode = primarySetPowerMode, + .WaitVSync = primaryWaitVSync, + .GetScreenSize = primaryGetScreenSize, +}; + +/******************************************************************************/ + +static DFBResult dfb_fbdev_read_modes( void ); +static DFBResult dfb_fbdev_set_gamma_ramp( DFBSurfacePixelFormat format ); +static DFBResult dfb_fbdev_set_palette( CorePalette *palette ); +static DFBResult dfb_fbdev_set_rgb332_palette( void ); +static DFBResult dfb_fbdev_pan( int xoffset, int yoffset, bool onsync ); +static DFBResult dfb_fbdev_blank( int level ); +static void dfb_fbdev_var_to_mode( const struct fb_var_screeninfo *var, + VideoMode *mode ); + +/******************************************************************************/ + +static inline +void waitretrace (void) +{ +#if defined(HAVE_INB_OUTB_IOPL) + if (iopl(3)) + return; + + if (!(inb (0x3cc) & 1)) { + while ((inb (0x3ba) & 0x8)) + ; + + while (!(inb (0x3ba) & 0x8)) + ; + } + else { + while ((inb (0x3da) & 0x8)) + ; + + while (!(inb (0x3da) & 0x8)) + ; + } +#endif +} + +/******************************************************************************/ + +static DFBResult dfb_fbdev_open( void ) +{ + DFBResult error_result = DFB_FAILURE; + + if (dfb_config->fb_device) { + dfb_fbdev->fd = open( dfb_config->fb_device, O_RDWR ); + if (dfb_fbdev->fd < 0) { + D_PERROR( "DirectFB/FBDev: Error opening '%s'!\n", + dfb_config->fb_device); + + error_result = errno2result( errno ); + goto error; + } + } + else if (getenv( "FRAMEBUFFER" ) && *getenv( "FRAMEBUFFER" ) != '\0') { + dfb_fbdev->fd = open( getenv ("FRAMEBUFFER"), O_RDWR ); + if (dfb_fbdev->fd < 0) { + D_PERROR( "DirectFB/FBDev: Error opening '%s'!\n", + getenv ("FRAMEBUFFER")); + + error_result = errno2result( errno ); + goto error; + } + } + else { + dfb_fbdev->fd = direct_try_open( "/dev/fb0", "/dev/fb/0", O_RDWR, true ); + if (dfb_fbdev->fd < 0) { + D_ERROR( "DirectFB/FBDev: Error opening framebuffer device!\n" ); + D_ERROR( "DirectFB/FBDev: Use 'fbdev' option or set FRAMEBUFFER environment variable.\n" ); + error_result = DFB_INIT; + goto error; + } + } + + /* should be closed automatically in children upon exec(...) */ + if (fcntl( dfb_fbdev->fd, F_SETFD, FD_CLOEXEC ) < 0) + { + D_PERROR( "Fusion/Init: Setting FD_CLOEXEC flag failed!\n" ); + goto error; + } + + return DFB_OK; +error: + return error_result; +} + +/******************************************************************************/ + +static void +dfb_fbdev_get_pci_info( FBDevShared *shared ) +{ + char buf[512]; + int vendor = -1; + int model = -1; + +#ifdef USE_SYSFS + if (!sysfs_get_mnt_path( buf, 512 )) { + struct sysfs_class_device *classdev; + struct sysfs_device *device; + struct sysfs_attribute *attr; + char *fbdev; + char dev[5] = { 'f', 'b', '0', 0, 0 }; + + fbdev = dfb_config->fb_device; + if (!fbdev) + fbdev = getenv( "FRAMEBUFFER" ); + + if (fbdev) { + if (!strncmp( fbdev, "/dev/fb/", 8 )) + snprintf( dev, 5, "fb%s", fbdev+8 ); + else if (!strncmp( fbdev, "/dev/fb", 7 )) + snprintf( dev, 5, "fb%s", fbdev+7 ); + } + + classdev = sysfs_open_class_device( "graphics", dev ); + if (classdev) { + device = sysfs_get_classdev_device( classdev ); + + if (device) { + attr = sysfs_get_device_attr( device, "vendor" ); + if (attr) + sscanf( attr->value, "0x%04x", &vendor ); + + attr = sysfs_get_device_attr( device, "device" ); + if (attr) + sscanf( attr->value, "0x%04x", &model ); + + if (vendor != -1 && model != -1) { + sscanf( device->name, "0000:%02x:%02x.%1x", + &shared->pci.bus, + &shared->pci.dev, + &shared->pci.func ); + + shared->device.vendor = vendor; + shared->device.model = model; + } + } + + sysfs_close_class_device( classdev ); + } + } +#endif /* USE_SYSFS */ + + /* try /proc interface */ + if (vendor == -1 || model == -1) { + FILE *fp; + int id; + int bus; + int dev; + int func; + + fp = fopen( "/proc/bus/pci/devices", "r" ); + if (!fp) { + D_DEBUG( "DirectFB/FBDev: " + "couldn't access /proc/bus/pci/devices!\n" ); + return; + } + + while (fgets( buf, 512, fp )) { + if (sscanf( buf, "%04x\t%04x%04x", &id, &vendor, &model ) == 3) { + bus = (id & 0xff00) >> 8; + dev = (id & 0x00ff) >> 3; + func = (id & 0x0007); + + if (bus == dfb_config->pci.bus && + dev == dfb_config->pci.dev && + func == dfb_config->pci.func) + { + shared->pci.bus = bus; + shared->pci.dev = dev; + shared->pci.func = func; + + shared->device.vendor = vendor; + shared->device.model = model; + + break; + } + } + } + + fclose( fp ); + } +} + + +/** public **/ + +static void +system_get_info( CoreSystemInfo *info ) +{ + info->type = CORE_FBDEV; + info->caps = CSCAPS_ACCELERATION; + + snprintf( info->name, DFB_CORE_SYSTEM_INFO_NAME_LENGTH, "FBDev" ); +} + +static DFBResult +system_initialize( CoreDFB *core, void **data ) +{ + DFBResult ret; + CoreScreen *screen; + long page_size; + FBDevShared *shared = NULL; + FusionSHMPoolShared *pool; + FusionSHMPoolShared *pool_data; + + D_ASSERT( dfb_fbdev == NULL ); + + pool = dfb_core_shmpool( core ); + pool_data = dfb_core_shmpool_data( core ); + + dfb_fbdev = D_CALLOC( 1, sizeof(FBDev) ); + if (!dfb_fbdev) + return D_OOM(); + + dfb_fbdev->fd = -1; + + shared = (FBDevShared*) SHCALLOC( pool, 1, sizeof(FBDevShared) ); + if (!shared) { + ret = D_OOSHM(); + goto error; + } + + shared->shmpool = pool; + shared->shmpool_data = pool_data; + + fusion_arena_add_shared_field( dfb_core_arena( core ), "fbdev", shared ); + + dfb_fbdev->core = core; + dfb_fbdev->shared = shared; + + page_size = direct_pagesize(); + + shared->page_mask = page_size < 0 ? 0 : (page_size - 1); + + ret = dfb_fbdev_open(); + if (ret) + goto error; + + if (dfb_config->vt) { + ret = dfb_vt_initialize(); + if (ret) + goto error; + } + + ret = DFB_INIT; + + /* Retrieve fixed informations like video ram size */ + if (ioctl( dfb_fbdev->fd, FBIOGET_FSCREENINFO, &shared->fix ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not get fixed screen information!\n" ); + goto error; + } + + D_INFO( "DirectFB/FBDev: Found '%s' (ID %d) with frame buffer at 0x%08lx, %dk (MMIO 0x%08lx, %dk)\n", + shared->fix.id, shared->fix.accel, + shared->fix.smem_start, shared->fix.smem_len >> 10, + shared->fix.mmio_start, shared->fix.mmio_len >> 10 ); + + /* Map the framebuffer */ + dfb_fbdev->framebuffer_base = mmap( NULL, shared->fix.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, 0 ); + if (dfb_fbdev->framebuffer_base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: " + "Could not mmap the framebuffer!\n"); + dfb_fbdev->framebuffer_base = NULL; + goto error; + } + + if (ioctl( dfb_fbdev->fd, FBIOGET_VSCREENINFO, &shared->orig_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not get variable screen information!\n" ); + goto error; + } + + shared->current_var = shared->orig_var; + shared->current_var.accel_flags = 0; + + if (ioctl( dfb_fbdev->fd, FBIOPUT_VSCREENINFO, &shared->current_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not disable console acceleration!\n" ); + goto error; + } + + dfb_fbdev_var_to_mode( &shared->current_var, + &shared->current_mode ); + + shared->orig_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->orig_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->orig_cmap.start = 0; + shared->orig_cmap.len = 256; + shared->orig_cmap.red = shared->orig_cmap_memory + 256 * 2 * 0; + shared->orig_cmap.green = shared->orig_cmap_memory + 256 * 2 * 1; + shared->orig_cmap.blue = shared->orig_cmap_memory + 256 * 2 * 2; + shared->orig_cmap.transp = shared->orig_cmap_memory + 256 * 2 * 3; + + if (ioctl( dfb_fbdev->fd, FBIOGETCMAP, &shared->orig_cmap ) < 0) { + D_DEBUG( "DirectFB/FBDev: " + "Could not retrieve palette for backup!\n" ); + + memset( &shared->orig_cmap, 0, sizeof(shared->orig_cmap) ); + + SHFREE( pool_data, shared->orig_cmap_memory ); + shared->orig_cmap_memory = NULL; + } + + shared->temp_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->temp_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->temp_cmap.start = 0; + shared->temp_cmap.len = 256; + shared->temp_cmap.red = shared->temp_cmap_memory + 256 * 2 * 0; + shared->temp_cmap.green = shared->temp_cmap_memory + 256 * 2 * 1; + shared->temp_cmap.blue = shared->temp_cmap_memory + 256 * 2 * 2; + shared->temp_cmap.transp = shared->temp_cmap_memory + 256 * 2 * 3; + + shared->current_cmap_memory = SHMALLOC( pool_data, 256 * 2 * 4 ); + if (!shared->current_cmap_memory) { + ret = D_OOSHM(); + goto error; + } + + shared->current_cmap.start = 0; + shared->current_cmap.len = 256; + shared->current_cmap.red = shared->current_cmap_memory + 256 * 2 * 0; + shared->current_cmap.green = shared->current_cmap_memory + 256 * 2 * 1; + shared->current_cmap.blue = shared->current_cmap_memory + 256 * 2 * 2; + shared->current_cmap.transp = shared->current_cmap_memory + 256 * 2 * 3; + + dfb_fbdev_get_pci_info( shared ); + + if (dfb_config->agp) { + /* Do not fail here, AGP slot could be unavailable */ + ret = dfb_agp_initialize(); + if (ret) { + D_DEBUG( "DirectFB/FBDev: dfb_agp_initialize()\n\t->%s\n", + DirectFBErrorString( ret ) ); + ret = DFB_OK; + } + } + + fusion_call_init( &shared->fbdev_ioctl, + fbdev_ioctl_call_handler, NULL, dfb_core_world(core) ); + + dfb_surface_pool_initialize( core, &fbdevSurfacePoolFuncs, &dfb_fbdev->shared->pool ); + + /* Register primary screen functions */ + screen = dfb_screens_register( NULL, NULL, &primaryScreenFuncs ); + + /* Register primary layer functions */ + dfb_layers_register( screen, NULL, &primaryLayerFuncs ); + + *data = dfb_fbdev; + + return DFB_OK; + + +error: + if (shared) { + if (shared->orig_cmap_memory) + SHFREE( pool_data, shared->orig_cmap_memory ); + + if (shared->temp_cmap_memory) + SHFREE( pool_data, shared->temp_cmap_memory ); + + if (shared->current_cmap_memory) + SHFREE( pool_data, shared->current_cmap_memory ); + + SHFREE( pool, shared ); + } + + if (dfb_fbdev->framebuffer_base) + munmap( dfb_fbdev->framebuffer_base, shared->fix.smem_len ); + + if (dfb_fbdev->fd != -1) + close( dfb_fbdev->fd ); + + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return ret; +} + +static DFBResult +system_join( CoreDFB *core, void **data ) +{ + DFBResult ret; + CoreScreen *screen; + void *shared; + + D_ASSERT( dfb_fbdev == NULL ); + + if (dfb_config->vt) { + ret = dfb_vt_join(); + if (ret) + return ret; + } + + dfb_fbdev = D_CALLOC( 1, sizeof(FBDev) ); + if (!dfb_fbdev) + return D_OOM(); + + fusion_arena_get_shared_field( dfb_core_arena( core ), + "fbdev", &shared ); + + dfb_fbdev->core = core; + dfb_fbdev->shared = shared; + + /* Open framebuffer device */ + ret = dfb_fbdev_open(); + if (ret) { + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + return ret; + } + + /* Map the framebuffer */ + dfb_fbdev->framebuffer_base = mmap( NULL, dfb_fbdev->shared->fix.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, 0 ); + if (dfb_fbdev->framebuffer_base == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: " + "Could not mmap the framebuffer!\n"); + close( dfb_fbdev->fd ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_INIT; + } + + /* Open AGP device */ + ret = dfb_agp_join(); + if (ret) { + D_ERROR( "DirectFB/FBDev: Could not join AGP!\n" ); + munmap( dfb_fbdev->framebuffer_base, + dfb_fbdev->shared->fix.smem_len ); + close( dfb_fbdev->fd ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return ret; + } + + dfb_surface_pool_join( core, dfb_fbdev->shared->pool, &fbdevSurfacePoolFuncs ); + + /* Register primary screen functions */ + screen = dfb_screens_register( NULL, NULL, &primaryScreenFuncs ); + + /* Register primary layer functions */ + dfb_layers_register( screen, NULL, &primaryLayerFuncs ); + + *data = dfb_fbdev; + + return DFB_OK; +} + +static DFBResult +system_shutdown( bool emergency ) +{ + DFBResult ret; + VideoMode *m; + FBDevShared *shared; + FusionSHMPoolShared *pool; + + D_ASSERT( dfb_fbdev != NULL ); + + shared = dfb_fbdev->shared; + + D_ASSERT( shared != NULL ); + + pool = shared->shmpool; + + D_ASSERT( pool != NULL ); + + m = shared->modes; + while (m) { + VideoMode *next = m->next; + SHFREE( pool, m ); + m = next; + } + + if (ioctl( dfb_fbdev->fd, FBIOPUT_VSCREENINFO, &shared->orig_var ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not restore variable screen information!\n" ); + } + + if (shared->orig_cmap.len) { + if (ioctl( dfb_fbdev->fd, FBIOPUTCMAP, &shared->orig_cmap ) < 0) + D_DEBUG( "DirectFB/FBDev: " + "Could not restore palette!\n" ); + } + + if (shared->orig_cmap_memory) + SHFREE( shared->shmpool_data, shared->orig_cmap_memory ); + + if (shared->temp_cmap_memory) + SHFREE( shared->shmpool_data, shared->temp_cmap_memory ); + + if (shared->current_cmap_memory) + SHFREE( shared->shmpool_data, shared->current_cmap_memory ); + + fusion_call_destroy( &shared->fbdev_ioctl ); + + dfb_agp_shutdown(); + + dfb_surface_pool_destroy( dfb_fbdev->shared->pool ); + + munmap( dfb_fbdev->framebuffer_base, shared->fix.smem_len ); + + if (dfb_config->vt) { + ret = dfb_vt_shutdown( emergency ); + if (ret) + return ret; + } + + close( dfb_fbdev->fd ); + + SHFREE( pool, shared ); + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_OK; +} + +static DFBResult +system_leave( bool emergency ) +{ + DFBResult ret; + + D_ASSERT( dfb_fbdev != NULL ); + + dfb_agp_leave(); + + dfb_surface_pool_leave( dfb_fbdev->shared->pool ); + + munmap( dfb_fbdev->framebuffer_base, + dfb_fbdev->shared->fix.smem_len ); + + if (dfb_config->vt) { + ret = dfb_vt_leave( emergency ); + if (ret) + return ret; + } + + close( dfb_fbdev->fd ); + + D_FREE( dfb_fbdev ); + dfb_fbdev = NULL; + + return DFB_OK; +} + +static DFBResult +system_suspend( void ) +{ + return DFB_OK; +} + +static DFBResult +system_resume( void ) +{ + return DFB_OK; +} + +/******************************************************************************/ + +static volatile void * +system_map_mmio( unsigned int offset, + int length ) +{ + void *addr; + + if (length <= 0) + length = dfb_fbdev->shared->fix.mmio_len; + + addr = mmap( NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, + dfb_fbdev->fd, dfb_fbdev->shared->fix.smem_len + offset ); + if (addr == MAP_FAILED) { + D_PERROR( "DirectFB/FBDev: Could not mmap MMIO region " + "(offset %d, length %d)!\n", offset, length ); + return NULL; + } + + return(volatile void*) ((u8*) addr + (dfb_fbdev->shared->fix.mmio_start & + dfb_fbdev->shared->page_mask)); +} + +static void +system_unmap_mmio( volatile void *addr, + int length ) +{ + if (length <= 0) + length = dfb_fbdev->shared->fix.mmio_len; + + if (munmap( (void*) ((u8*) addr - (dfb_fbdev->shared->fix.mmio_start & + dfb_fbdev->shared->page_mask)), length ) < 0) + D_PERROR( "DirectFB/FBDev: Could not unmap MMIO region " + "at %p (length %d)!\n", addr, length ); +} + +static int +system_get_accelerator( void ) +{ +#ifdef FB_ACCEL_MATROX_MGAG400 + if (!strcmp( dfb_fbdev->shared->fix.id, "MATROX DH" )) + return FB_ACCEL_MATROX_MGAG400; +#endif +#ifdef FB_ACCEL_EP9X + if (!strcmp( dfb_fbdev->shared->fix.id, "ep9xfb" )) + return FB_ACCEL_EP9X; +#endif + + if (dfb_config->accelerator) + return dfb_config->accelerator; + + if (dfb_fbdev->shared->fix.mmio_len > 0) + return dfb_fbdev->shared->fix.accel; + return -1; +} + +static VideoMode * +system_get_modes( void ) +{ + return dfb_fbdev->shared->modes; +} + +static VideoMode * +system_get_current_mode( void ) +{ + return &dfb_fbdev->shared->current_mode; +} + +static DFBResult +system_thread_init( void ) +{ + if (dfb_config->block_all_signals) + direct_signals_block_all(); + + return DFB_OK; +} + +static bool +system_input_filter( CoreInputDevice *device, + DFBInputEvent *event ) +{ + if (dfb_config->vt && dfb_config->vt_switching) { + switch (event->type) { + case DIET_KEYPRESS: + if (DFB_KEY_TYPE(event->key_symbol) == DIKT_FUNCTION && + event->modifiers == (DIMM_CONTROL | DIMM_ALT)) + return dfb_vt_switch( event->key_symbol - DIKS_F1 + 1 ); + + break; + + case DIET_KEYRELEASE: + if (DFB_KEY_TYPE(event->key_symbol) == DIKT_FUNCTION && + event->modifiers == (DIMM_CONTROL | DIMM_ALT)) + return true; + + break; + + default: + break; + } + } + + return false; +} + +static unsigned long +system_video_memory_physical( unsigned int offset ) +{ + return dfb_fbdev->shared->fix.smem_start + offset; +} + +static void * +system_video_memory_virtual( unsigned int offset ) +{ + return(void*)((u8*)(dfb_fbdev->framebuffer_base) + offset); +} + +static unsigned int +system_videoram_length( void ) +{ + return dfb_fbdev->shared->fix.smem_len; +} + +static unsigned long +system_aux_memory_physical( unsigned int offset ) +{ + if (dfb_fbdev->shared->agp) + return dfb_fbdev->shared->agp->info.aper_base + offset; + return 0; +} + +static void * +system_aux_memory_virtual( unsigned int offset ) +{ + if (dfb_fbdev->agp) + return (void*)(u8*)dfb_fbdev->agp->base + offset; + return NULL; +} + +static unsigned int +system_auxram_length( void ) +{ + if (dfb_fbdev->shared->agp) + return dfb_fbdev->shared->agp->agp_mem; + return 0; +} + +static void +system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ) +{ + *ret_bus = dfb_fbdev->shared->pci.bus; + *ret_dev = dfb_fbdev->shared->pci.dev; + *ret_func = dfb_fbdev->shared->pci.func; +} + +static void +system_get_deviceid( unsigned int *ret_vendor_id, + unsigned int *ret_device_id ) +{ + *ret_vendor_id = dfb_fbdev->shared->device.vendor; + *ret_device_id = dfb_fbdev->shared->device.model; +} + +/******************************************************************************/ + +static DFBResult +init_modes( void ) +{ + dfb_fbdev_read_modes(); + + if (!dfb_fbdev->shared->modes) { + /* try to use current mode*/ + dfb_fbdev->shared->modes = (VideoMode*) SHCALLOC( dfb_fbdev->shared->shmpool, + 1, sizeof(VideoMode) ); + if (!dfb_fbdev->shared->modes) + return D_OOSHM(); + + *dfb_fbdev->shared->modes = dfb_fbdev->shared->current_mode; + + if (dfb_fbdev_test_mode_simple(dfb_fbdev->shared->modes)) { + D_ERROR("DirectFB/FBDev: " + "No supported modes found in /etc/fb.modes and " + "current mode not supported!\n"); + + D_ERROR( "DirectFB/FBDev: Current mode's pixelformat: " + "rgba %d/%d, %d/%d, %d/%d, %d/%d (%dbit)\n", + dfb_fbdev->shared->orig_var.red.length, + dfb_fbdev->shared->orig_var.red.offset, + dfb_fbdev->shared->orig_var.green.length, + dfb_fbdev->shared->orig_var.green.offset, + dfb_fbdev->shared->orig_var.blue.length, + dfb_fbdev->shared->orig_var.blue.offset, + dfb_fbdev->shared->orig_var.transp.length, + dfb_fbdev->shared->orig_var.transp.offset, + dfb_fbdev->shared->orig_var.bits_per_pixel ); + + return DFB_INIT; + } + } + + return DFB_OK; +} + +/******************************************************************************/ + +static DFBResult +primaryInitScreen( CoreScreen *screen, + CoreGraphicsDevice *device, + void *driver_data, + void *screen_data, + DFBScreenDescription *description ) +{ + /* Set the screen capabilities. */ + description->caps = DSCCAPS_VSYNC | DSCCAPS_POWER_MANAGEMENT; + + /* Set the screen name. */ + snprintf( description->name, + DFB_SCREEN_DESC_NAME_LENGTH, "FBDev Primary Screen" ); + + return DFB_OK; +} + +static DFBResult +primarySetPowerMode( CoreScreen *screen, + void *driver_data, + void *screen_data, + DFBScreenPowerMode mode ) +{ + int level; + + switch (mode) { + case DSPM_OFF: + level = 4; + break; + case DSPM_SUSPEND: + level = 3; + break; + case DSPM_STANDBY: + level = 2; + break; + case DSPM_ON: + level = 0; + break; + default: + return DFB_INVARG; + } + + return dfb_fbdev_blank( level ); +} + +static DFBResult +primaryWaitVSync( CoreScreen *screen, + void *driver_data, + void *screen_data ) +{ + static const int zero = 0; + + if (dfb_config->pollvsync_none) + return DFB_OK; + + if (ioctl( dfb_fbdev->fd, FBIO_WAITFORVSYNC, &zero )) + waitretrace(); + + return DFB_OK; +} + +static DFBResult +primaryGetScreenSize( CoreScreen *screen, + void *driver_data, + void *screen_data, + int *ret_width, + int *ret_height ) +{ + D_ASSERT( dfb_fbdev != NULL ); + D_ASSERT( dfb_fbdev->shared != NULL ); + + *ret_width = dfb_fbdev->shared->current_mode.xres; + *ret_height = dfb_fbdev->shared->current_mode.yres; + + return DFB_OK; +} + +/******************************************************************************/ + +static int +primaryLayerDataSize( void ) +{ + return 0; +} + +static int +primaryRegionDataSize( void ) +{ + return 0; +} + +static DFBResult +primaryInitLayer( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ) +{ + DFBResult ret; + VideoMode *default_mode; + + /* initialize mode table */ + ret = init_modes(); + if (ret) + return ret; + + default_mode = dfb_fbdev->shared->modes; + + /* set capabilities and type */ + description->caps = DLCAPS_SURFACE | DLCAPS_CONTRAST | + DLCAPS_SATURATION | DLCAPS_BRIGHTNESS; + description->type = DLTF_GRAPHICS; + + /* set name */ + snprintf( description->name, + DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "FBDev Primary Layer" ); + + /* fill out default color adjustment */ + adjustment->flags = DCAF_BRIGHTNESS | DCAF_CONTRAST | DCAF_SATURATION; + adjustment->brightness = 0x8000; + adjustment->contrast = 0x8000; + adjustment->saturation = 0x8000; + + /* fill out the default configuration */ + config->flags = DLCONF_WIDTH | DLCONF_HEIGHT | + DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE; + config->buffermode = DLBM_FRONTONLY; + config->width = dfb_config->mode.width ? dfb_config->mode.width : default_mode->xres; + config->height = dfb_config->mode.height ? dfb_config->mode.height : default_mode->yres; + + if (dfb_config->mode.format) + config->pixelformat = dfb_config->mode.format; + else + config->pixelformat = dfb_pixelformat_for_depth( default_mode->bpp ); + + return DFB_OK; +} + +static DFBResult +primarySetColorAdjustment( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adjustment ) +{ + struct fb_cmap *cmap = &dfb_fbdev->shared->current_cmap; + struct fb_cmap *temp = &dfb_fbdev->shared->temp_cmap; + int contrast = adjustment->contrast >> 8; + int brightness = (adjustment->brightness >> 8) - 128; + int saturation = adjustment->saturation >> 8; + int r, g, b, i; + + if (dfb_fbdev->shared->fix.visual != FB_VISUAL_DIRECTCOLOR) + return DFB_UNIMPLEMENTED; + + /* Use gamma ramp to set color attributes */ + for (i = 0; i < (int)cmap->len; i++) { + r = cmap->red[i]; + g = cmap->green[i]; + b = cmap->blue[i]; + r >>= 8; + g >>= 8; + b >>= 8; + + /* + * Brightness Adjustment: Increase/Decrease each color channels + * by a constant amount as specified by value of brightness. + */ + if (adjustment->flags & DCAF_BRIGHTNESS) { + r += brightness; + g += brightness; + b += brightness; + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + + /* + * Contrast Adjustment: We increase/decrease the "separation" + * between colors in proportion to the value specified by the + * contrast control. Decreasing the contrast has a side effect + * of decreasing the brightness. + */ + + if (adjustment->flags & DCAF_CONTRAST) { + /* Increase contrast */ + if (contrast > 128) { + int c = contrast - 128; + + r = ((r + c/2)/c) * c; + g = ((g + c/2)/c) * c; + b = ((b + c/2)/c) * c; + } + /* Decrease contrast */ + else if (contrast < 127) { + r = (r * contrast) >> 7; + g = (g * contrast) >> 7; + b = (b * contrast) >> 7; + } + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + + /* + * Saturation Adjustment: This is is a better implementation. + * Saturation is implemented by "mixing" a proportion of medium + * gray to the color value. On the other side, "removing" + * a proportion of medium gray oversaturates the color. + */ + if (adjustment->flags & DCAF_SATURATION) { + if (saturation > 128) { + int gray = saturation - 128; + int color = 128 - gray; + + r = ((r - gray) << 7) / color; + g = ((g - gray) << 7) / color; + b = ((b - gray) << 7) / color; + } + else if (saturation < 128) { + int color = saturation; + int gray = 128 - color; + + r = ((r * color) >> 7) + gray; + g = ((g * color) >> 7) + gray; + b = ((b * color) >> 7) + gray; + } + + r = CLAMP( r, 0, 255 ); + g = CLAMP( g, 0, 255 ); + b = CLAMP( b, 0, 255 ); + } + r |= r << 8; + g |= g << 8; + b |= b << 8; + + temp->red[i] = (unsigned short)r; + temp->green[i] = (unsigned short)g; + temp->blue[i] = (unsigned short)b; + } + + temp->len = cmap->len; + temp->start = cmap->start; + if (FBDEV_IOCTL( FBIOPUTCMAP, temp ) < 0) { + D_PERROR( "DirectFB/FBDev: Could not set the palette!\n" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +const VideoMode * +dfb_fbdev_find_mode( int width, int height ) +{ + FBDevShared *shared = dfb_fbdev->shared; + const VideoMode *videomode = shared->modes; + const VideoMode *highest = NULL; + + while (videomode) { + if (videomode->xres == width && videomode->yres == height) { + if (!highest || highest->priority < videomode->priority) + highest = videomode; + } + + videomode = videomode->next; + } + + if (!highest) + D_ERROR( "FBDev/Mode: No mode found for %dx%d!\n", width, height ); + + return highest; +} + +static DFBResult +primaryTestRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ) +{ + FBDevShared *shared = dfb_fbdev->shared; + CoreLayerRegionConfigFlags fail = CLRCF_NONE; + const VideoMode *mode; + + D_DEBUG_AT( FBDev_Mode, "%s( %dx%d, %s )\n", __FUNCTION__, + config->source.w, config->source.h, dfb_pixelformat_name(config->format) ); + + mode = dfb_fbdev_find_mode( config->source.w, config->source.h ); + + if (!mode || dfb_fbdev_test_mode( mode, config )) + fail |= CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_BUFFERMODE; + + if (config->options) + fail |= CLRCF_OPTIONS; + + if ((config->source.x && !shared->fix.xpanstep) || + (config->source.y && !shared->fix.ypanstep && !shared->fix.ywrapstep)) + fail |= CLRCF_SOURCE; + + if (failed) + *failed = fail; + + if (fail) + return DFB_UNSUPPORTED; + + return DFB_OK; +} + +static DFBResult +primaryAddRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config ) +{ + return DFB_OK; +} + +static DFBResult +primarySetRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + FBDevShared *shared = dfb_fbdev->shared; + + if (updated & CLRCF_SOURCE) { + if (config->source.w == shared->current_var.xres && config->source.h == shared->current_var.yres) { + ret = dfb_fbdev_pan( config->source.x, lock->offset / lock->pitch + config->source.y, true ); + if (ret) + return ret; + } + else { + const VideoMode *mode; + + D_INFO( "FBDev/Mode: Setting %dx%d %s\n", config->source.w, config->source.h, + dfb_pixelformat_name( surface->config.format ) ); + + mode = dfb_fbdev_find_mode( config->source.w, config->source.h ); + if (!mode) + return DFB_UNSUPPORTED; + + ret = dfb_fbdev_set_mode( mode, surface, config->source.x, + lock->offset / lock->pitch + config->source.y ); + if (ret) + return ret; + } + } + + if ((updated & CLRCF_PALETTE) && palette) + dfb_fbdev_set_palette( palette ); + + /* remember configuration */ + shared->config = *config; + + return DFB_OK; +} + +static DFBResult +primaryRemoveRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ) +{ + return DFB_OK; +} + +static DFBResult +primaryFlipRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreLayerRegionConfig *config = &dfb_fbdev->shared->config; + + if (((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) && + !dfb_config->pollvsync_after) + dfb_screen_wait_vsync( dfb_screens_at(DSCID_PRIMARY) ); + + ret = dfb_fbdev_pan( config->source.x, + lock->offset / lock->pitch + config->source.y, + (flags & DSFLIP_WAITFORSYNC) == DSFLIP_ONSYNC ); + if (ret) + return ret; + + if ((flags & DSFLIP_WAIT) && + (dfb_config->pollvsync_after || !(flags & DSFLIP_ONSYNC))) + dfb_screen_wait_vsync( dfb_screens_at(DSCID_PRIMARY) ); + + dfb_surface_flip( surface, false ); + + return DFB_OK; +} + +/** fbdev internal **/ + +static void +dfb_fbdev_var_to_mode( const struct fb_var_screeninfo *var, + VideoMode *mode ) +{ + mode->xres = var->xres; + mode->yres = var->yres; + mode->bpp = var->bits_per_pixel; + mode->hsync_len = var->hsync_len; + mode->vsync_len = var->vsync_len; + mode->left_margin = var->left_margin; + mode->right_margin = var->right_margin; + mode->upper_margin = var->upper_margin; + mode->lower_margin = var->lower_margin; + mode->pixclock = var->pixclock; + mode->hsync_high = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0; + mode->vsync_high = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0; + mode->csync_high = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? 1 : 0; + mode->sync_on_green = (var->sync & FB_SYNC_ON_GREEN) ? 1 : 0; + mode->external_sync = (var->sync & FB_SYNC_EXT) ? 1 : 0; + mode->broadcast = (var->sync & FB_SYNC_BROADCAST) ? 1 : 0; + mode->laced = (var->vmode & FB_VMODE_INTERLACED) ? 1 : 0; + mode->doubled = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0; +} + +#if 0 +static int dfb_fbdev_compatible_format( struct fb_var_screeninfo *var, + int al, int rl, int gl, int bl, + int ao, int ro, int go, int bo ) +{ + int ah, rh, gh, bh; + int vah, vrh, vgh, vbh; + + ah = al + ao - 1; + rh = rl + ro - 1; + gh = gl + go - 1; + bh = bl + bo - 1; + + vah = var->transp.length + var->transp.offset - 1; + vrh = var->red.length + var->red.offset - 1; + vgh = var->green.length + var->green.offset - 1; + vbh = var->blue.length + var->blue.offset - 1; + + if ((!al || (ah == vah && al >= (int)var->transp.length)) && + (!rl || (rh == vrh && rl >= (int)var->red.length)) && + (!gl || (gh == vgh && gl >= (int)var->green.length)) && + (!bl || (bh == vbh && bl >= (int)var->blue.length))) + return 1; + + return 0; +} + +static DFBSurfacePixelFormat dfb_fbdev_get_pixelformat( struct fb_var_screeninfo *var ) +{ + switch (var->bits_per_pixel) { + + case 8: +/* + This check is omitted, since we want to use RGB332 even if the + hardware uses a palette (in that case we initialize a calculated + one to have correct colors) + + if (fbdev_compatible_format( var, 0, 3, 3, 2, 0, 5, 2, 0 ))*/ + + return DSPF_RGB332; + + case 15: + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 10, 5, 0 )) + return DSPF_RGB555; + + if(dfb_fbdev_compatible_format( var, 1, 5, 5, 5, 15, 10, 5, 0 )) + return DSPF_ARGB1555; + + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 0, 5, 10 )) + return DSPF_BGR555; + + break; + + case 16: + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 10, 5, 0 )) + return DSPF_RGB555; + + if(dfb_fbdev_compatible_format( var, 1, 5, 5, 5, 15, 10, 5, 0 )) + return DSPF_ARGB1555; + + if (dfb_fbdev_compatible_format( var, 4, 4, 4, 4, 12, 8, 4, 0 )) + return DSPF_ARGB4444; + + if (dfb_fbdev_compatible_format( var, 4, 4, 4, 4, 0, 12, 8, 4 )) + return DSPF_RGBA4444; + + if (dfb_fbdev_compatible_format( var, 0, 4, 4, 4, 0, 8, 4, 0 )) + return DSPF_RGB444; + + if (dfb_fbdev_compatible_format( var, 0, 5, 6, 5, 0, 11, 5, 0 )) + return DSPF_RGB16; + + if (dfb_fbdev_compatible_format( var, 0, 5, 5, 5, 0, 0, 5, 10 )) + return DSPF_BGR555; + + break; + + case 18: + if (dfb_fbdev_compatible_format( var, 1, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB1666; + + if (dfb_fbdev_compatible_format( var, 6, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB6666; + + if (dfb_fbdev_compatible_format( var, 0, 6, 6, 6, 0, 12, 6, 0 )) + return DSPF_RGB18; + break; + + case 24: + if (dfb_fbdev_compatible_format( var, 0, 8, 8, 8, 0, 16, 8, 0 )) + return DSPF_RGB24; + + if (dfb_fbdev_compatible_format( var, 6, 6, 6, 6, 18, 12, 6, 0 )) + return DSPF_ARGB6666; + break; + + case 32: + if (dfb_fbdev_compatible_format( var, 0, 8, 8, 8, 0, 16, 8, 0 )) + return DSPF_RGB32; + + if (dfb_fbdev_compatible_format( var, 8, 8, 8, 8, 24, 16, 8, 0 )) + return DSPF_ARGB; + + break; + } + + D_ERROR( "DirectFB/FBDev: Unsupported pixelformat: " + "rgba %d/%d, %d/%d, %d/%d, %d/%d (%dbit)\n", + var->red.length, var->red.offset, + var->green.length, var->green.offset, + var->blue.length, var->blue.offset, + var->transp.length, var->transp.offset, + var->bits_per_pixel ); + + return DSPF_UNKNOWN; +} +#endif + +/* + * pans display (flips buffer) using fbdev ioctl + */ +static DFBResult +dfb_fbdev_pan( int xoffset, int yoffset, bool onsync ) +{ +// DFBResult ret; + int result; + struct fb_var_screeninfo *var; + FBDevShared *shared = dfb_fbdev->shared; + + if (!shared->fix.xpanstep && !shared->fix.ypanstep && !shared->fix.ywrapstep) + return DFB_OK; + + var = &shared->current_var; + + if (var->xres_virtual < xoffset + var->xres) { + D_ERROR( "DirectFB/FBDev: xres %d, vxres %d, xoffset %d\n", + var->xres, var->xres_virtual, xoffset ); + D_BUG( "panning buffer out of range" ); + return DFB_BUG; + } + + if (var->yres_virtual < yoffset + var->yres) { + D_ERROR( "DirectFB/FBDev: yres %d, vyres %d, offset %d\n", + var->yres, var->yres_virtual, yoffset ); + D_BUG( "panning buffer out of range" ); + return DFB_BUG; + } + + if (shared->fix.xpanstep) + var->xoffset = xoffset - (xoffset % shared->fix.xpanstep); + else + var->xoffset = 0; + + if (shared->fix.ywrapstep) { + var->yoffset = yoffset - (yoffset % shared->fix.ywrapstep); + var->vmode |= FB_VMODE_YWRAP; + } + else if (shared->fix.ypanstep) { + var->yoffset = yoffset - (yoffset % shared->fix.ypanstep); + var->vmode &= ~FB_VMODE_YWRAP; + } + else { + var->yoffset = 0; + } + + var->activate = onsync ? FB_ACTIVATE_VBL : FB_ACTIVATE_NOW; + +#if 0 + ret = fusion_call_execute( &shared->fbdev_ioctl, FCEF_NONE, FBIOPAN_DISPLAY, var, &result ); + if (ret) + return DFB_FUSION; + + if (result) { + errno = result; +#else + if (ioctl( dfb_fbdev->fd, FBIOPAN_DISPLAY, var ) < 0) { + result = errno; +#endif + D_PERROR( "DirectFB/FBDev: Panning display failed (x=%u y=%u ywrap=%d vbl=%d)!\n", + var->xoffset, var->yoffset, + (var->vmode & FB_VMODE_YWRAP) ? 1 : 0, + (var->activate & FB_ACTIVATE_VBL) ? 1 : 0); + + return errno2result(result); + } + + return DFB_OK; +} + +/* + * blanks display using fbdev ioctl + */ +static DFBResult +dfb_fbdev_blank( int level ) +{ + if (ioctl( dfb_fbdev->fd, FBIOBLANK, level ) < 0) { + D_PERROR( "DirectFB/FBDev: Display blanking failed!\n" ); + + return errno2result( errno ); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_mode_to_var( const VideoMode *mode, + DFBSurfacePixelFormat pixelformat, + unsigned int vxres, + unsigned int vyres, + unsigned int xoffset, + unsigned int yoffset, + DFBDisplayLayerBufferMode buffermode, + struct fb_var_screeninfo *ret_var ) +{ + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p )\n", __FUNCTION__, mode ); + + D_ASSERT( mode != NULL ); + D_ASSERT( ret_var != NULL ); + + D_DEBUG_AT( FBDev_Mode, " -> resolution %dx%d\n", mode->xres, mode->yres ); + D_DEBUG_AT( FBDev_Mode, " -> virtual %dx%d\n", vxres, vyres ); + D_DEBUG_AT( FBDev_Mode, " -> pixelformat %s\n", dfb_pixelformat_name(pixelformat) ); + D_DEBUG_AT( FBDev_Mode, " -> buffermode %s\n", + buffermode == DLBM_FRONTONLY ? "FRONTONLY" : + buffermode == DLBM_BACKVIDEO ? "BACKVIDEO" : + buffermode == DLBM_BACKSYSTEM ? "BACKSYSTEM" : + buffermode == DLBM_TRIPLE ? "TRIPLE" : "invalid!" ); + + /* Start from current information */ + var = shared->current_var; + var.activate = FB_ACTIVATE_NOW; + + /* Set timings */ + var.pixclock = mode->pixclock; + var.left_margin = mode->left_margin; + var.right_margin = mode->right_margin; + var.upper_margin = mode->upper_margin; + var.lower_margin = mode->lower_margin; + var.hsync_len = mode->hsync_len; + var.vsync_len = mode->vsync_len; + + /* Set resolution */ + var.xres = mode->xres; + var.yres = mode->yres; + var.xres_virtual = vxres; + var.yres_virtual = vyres; + + if (shared->fix.xpanstep) + var.xoffset = xoffset - (xoffset % shared->fix.xpanstep); + else + var.xoffset = 0; + + if (shared->fix.ywrapstep) + var.yoffset = yoffset - (yoffset % shared->fix.ywrapstep); + else if (shared->fix.ypanstep) + var.yoffset = yoffset - (yoffset % shared->fix.ypanstep); + else + var.yoffset = 0; + + /* Set buffer mode */ + switch (buffermode) { + case DLBM_TRIPLE: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + var.yres_virtual *= 3; + break; + + case DLBM_BACKVIDEO: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + var.yres_virtual *= 2; + break; + + case DLBM_BACKSYSTEM: + case DLBM_FRONTONLY: + break; + + default: + return DFB_UNSUPPORTED; + } + + /* Set pixel format */ + var.bits_per_pixel = DFB_BITS_PER_PIXEL(pixelformat); + var.transp.length = var.transp.offset = 0; + + switch (pixelformat) { + case DSPF_ARGB1555: + var.transp.length = 1; + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.transp.offset = 15; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_RGB555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 12; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGBA4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 0; + var.red.offset = 12; + var.green.offset = 8; + var.blue.offset = 4; + break; + + case DSPF_RGB444: + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGB32: + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_RGB16: + var.red.length = 5; + var.green.length = 6; + var.blue.length = 5; + var.red.offset = 11; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB: + case DSPF_AiRGB: + var.transp.length = 8; + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.transp.offset = 24; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_LUT8: + case DSPF_RGB24: + case DSPF_RGB332: + break; + + case DSPF_ARGB1666: + var.transp.length = 1; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_ARGB6666: + var.transp.length = 6; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_RGB18: + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + default: + return DFB_UNSUPPORTED; + } + + /* Set sync options */ + var.sync = 0; + if (mode->hsync_high) + var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->vsync_high) + var.sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->csync_high) + var.sync |= FB_SYNC_COMP_HIGH_ACT; + if (mode->sync_on_green) + var.sync |= FB_SYNC_ON_GREEN; + if (mode->external_sync) + var.sync |= FB_SYNC_EXT; + if (mode->broadcast) + var.sync |= FB_SYNC_BROADCAST; + + /* Set interlace/linedouble */ + var.vmode = 0; + if (mode->laced) + var.vmode |= FB_VMODE_INTERLACED; + if (mode->doubled) + var.vmode |= FB_VMODE_DOUBLE; + + *ret_var = var; + + return DFB_OK; +} + +DFBResult +dfb_fbdev_test_mode( const VideoMode *mode, + const CoreLayerRegionConfig *config ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + const DFBRectangle *source = &config->source; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p, config: %p )\n", __FUNCTION__, mode, config ); + + D_ASSERT( mode != NULL ); + D_ASSERT( config != NULL ); + + /* Is panning supported? */ + if (source->w != mode->xres && shared->fix.xpanstep == 0) + return DFB_UNSUPPORTED; + if (source->h != mode->yres && shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + ret = dfb_fbdev_mode_to_var( mode, config->format, config->width, config->height, + 0, 0, config->buffermode, &var ); + if (ret) + return ret; + + /* Enable test mode */ + var.activate = FB_ACTIVATE_TEST; + + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + dfb_gfxcard_unlock(); + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + return errno2result( erno ); + } + + dfb_gfxcard_unlock(); + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + return DFB_OK; +} + +DFBResult +dfb_fbdev_test_mode_simple( const VideoMode *mode ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p )\n", __FUNCTION__, mode ); + + D_ASSERT( mode != NULL ); + + ret = dfb_fbdev_mode_to_var( mode, dfb_pixelformat_for_depth(mode->bpp), mode->xres, mode->yres, + 0, 0, DLBM_FRONTONLY, &var ); + if (ret) + return ret; + + /* Enable test mode */ + var.activate = FB_ACTIVATE_TEST; + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + return errno2result( errno ); + } + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + return DFB_OK; +} + +static int num_video_buffers( CoreSurface *surface ) +{ + int i; + + for (i = 0; i < surface->num_buffers; i++) { + if (surface->buffers[i]->policy == CSP_SYSTEMONLY) + break; + } + + return i; +} + +DFBResult +dfb_fbdev_set_mode( const VideoMode *mode, + CoreSurface *surface, + unsigned int xoffset, + unsigned int yoffset ) +{ + DFBResult ret; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + DFBDisplayLayerBufferMode buffermode = DLBM_FRONTONLY; + const CoreSurfaceConfig *config = &surface->config ; + + D_DEBUG_AT( FBDev_Mode, "%s( mode: %p, config: %p )\n", __FUNCTION__, mode, config ); + + D_ASSERT( mode != NULL ); + D_ASSERT( config != NULL ); + + switch (num_video_buffers( surface )) { + case 3: + buffermode = DLBM_TRIPLE; + break; + case 2: + buffermode = DLBM_BACKVIDEO; + break; + case 1: + buffermode = DLBM_FRONTONLY; + break; + default: + D_BUG( "dfb_fbdev_set_mode() called with %d video buffers!", num_video_buffers( surface ) ); + return DFB_BUG; + } + + ret = dfb_fbdev_mode_to_var( mode, config->format, config->size.w, config->size.h, + xoffset, yoffset, buffermode, &var ); + if (ret) { + D_ERROR( "FBDev/Mode: Failed to switch to %dx%d %s (buffermode %d)\n", + config->size.w, config->size.h, dfb_pixelformat_name(config->format), buffermode ); + return ret; + } + + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + + dfb_gfxcard_unlock(); + + D_DEBUG_AT( FBDev_Mode, " => FAILED!\n" ); + + D_ERROR( "FBDev/Mode: Failed to switched to %dx%d (virtual %dx%d) at %d bit (%s)!\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(config->format) ); + + return errno2result( erno ); + } + + D_DEBUG_AT( FBDev_Mode, " => SUCCESS\n" ); + + shared->current_var = var; + dfb_fbdev_var_to_mode( &var, &shared->current_mode ); + + /* To get the new pitch */ + FBDEV_IOCTL( FBIOGET_FSCREENINFO, &shared->fix ); + + D_INFO( "FBDev/Mode: Switched to %dx%d (virtual %dx%d) at %d bit (%s), pitch %d\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(config->format), shared->fix.line_length ); + + if (config->format == DSPF_RGB332) + dfb_fbdev_set_rgb332_palette(); + else + dfb_fbdev_set_gamma_ramp( config->format ); + + /* invalidate original pan offset */ + shared->orig_var.xoffset = 0; + shared->orig_var.yoffset = 0; + + dfb_surfacemanager_adjust_heap_offset( dfb_fbdev->shared->manager, + var.yres_virtual * shared->fix.line_length ); + + dfb_gfxcard_after_set_var(); + + dfb_gfxcard_unlock(); + + return DFB_OK; +} + + +#if 0 +DFBResult +dfb_fbdev_set_mode( CoreSurface *surface, + VideoMode *mode, + CoreLayerRegionConfig *config ) +{ + unsigned int vxres, vyres; + struct fb_var_screeninfo var; + FBDevShared *shared = dfb_fbdev->shared; + DFBSurfacePixelFormat format; + + D_DEBUG("DirectFB/FBDev: dfb_fbdev_set_mode (surface: %p, " + "mode: %p, buffermode: %d)\n", surface, mode, + config ? config->buffermode : DLBM_FRONTONLY); + + if (!mode) + mode = &shared->current_mode; + + var = shared->current_var; + + if (config) { + DFBRectangle *source = &config->source; + + /* Is panning supported? */ + if (source->w != mode->xres && shared->fix.xpanstep == 0) + return DFB_UNSUPPORTED; + if (source->h != mode->yres && shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + + vxres = config->width; + vyres = config->height; + + var.xoffset = source->x; + var.yoffset = source->y; + + switch (config->buffermode) { + case DLBM_TRIPLE: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + vyres *= 3; + break; + + case DLBM_BACKVIDEO: + if (shared->fix.ypanstep == 0 && shared->fix.ywrapstep == 0) + return DFB_UNSUPPORTED; + vyres *= 2; + break; + + case DLBM_BACKSYSTEM: + case DLBM_FRONTONLY: + break; + + default: + return DFB_UNSUPPORTED; + } + + var.bits_per_pixel = DFB_BYTES_PER_PIXEL(config->format) * 8; + + var.transp.length = var.transp.offset = 0; + + switch (config->format) { + case DSPF_ARGB1555: + var.transp.length = 1; + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.transp.offset = 15; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_RGB555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 10; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_BGR555: + var.red.length = 5; + var.green.length = 5; + var.blue.length = 5; + var.red.offset = 0; + var.green.offset = 5; + var.blue.offset = 10; + break; + + case DSPF_ARGB4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 12; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGBA4444: + var.transp.length = 4; + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.transp.offset = 0; + var.red.offset = 12; + var.green.offset = 8; + var.blue.offset = 4; + break; + + case DSPF_RGB444: + var.red.length = 4; + var.green.length = 4; + var.blue.length = 4; + var.red.offset = 8; + var.green.offset = 4; + var.blue.offset = 0; + break; + + case DSPF_RGB32: + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_RGB16: + var.red.length = 5; + var.green.length = 6; + var.blue.length = 5; + var.red.offset = 11; + var.green.offset = 5; + var.blue.offset = 0; + break; + + case DSPF_ARGB: + case DSPF_AiRGB: + var.transp.length = 8; + var.red.length = 8; + var.green.length = 8; + var.blue.length = 8; + var.transp.offset = 24; + var.red.offset = 16; + var.green.offset = 8; + var.blue.offset = 0; + break; + + case DSPF_LUT8: + case DSPF_RGB24: + case DSPF_RGB332: + break; + + case DSPF_ARGB1666: + var.transp.length = 1; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_ARGB6666: + var.transp.length = 6; + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.transp.offset = 18; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + case DSPF_RGB18: + var.red.length = 6; + var.green.length = 6; + var.blue.length = 6; + var.red.offset = 12; + var.green.offset = 6; + var.blue.offset = 0; + break; + + default: + return DFB_UNSUPPORTED; + } + } + else { + vxres = mode->xres; + vyres = mode->yres; + + var.xoffset = 0; + var.yoffset = 0; + + var.bits_per_pixel = mode->bpp; + } + + var.activate = surface ? FB_ACTIVATE_NOW : FB_ACTIVATE_TEST; + + var.xres = mode->xres; + var.yres = mode->yres; + var.xres_virtual = vxres; + var.yres_virtual = vyres; + + var.pixclock = mode->pixclock; + var.left_margin = mode->left_margin; + var.right_margin = mode->right_margin; + var.upper_margin = mode->upper_margin; + var.lower_margin = mode->lower_margin; + var.hsync_len = mode->hsync_len; + var.vsync_len = mode->vsync_len; + + var.sync = 0; + if (mode->hsync_high) + var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->vsync_high) + var.sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->csync_high) + var.sync |= FB_SYNC_COMP_HIGH_ACT; + if (mode->sync_on_green) + var.sync |= FB_SYNC_ON_GREEN; + if (mode->external_sync) + var.sync |= FB_SYNC_EXT; + if (mode->broadcast) + var.sync |= FB_SYNC_BROADCAST; + + var.vmode = 0; + if (mode->laced) + var.vmode |= FB_VMODE_INTERLACED; + if (mode->doubled) + var.vmode |= FB_VMODE_DOUBLE; + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + if (FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &var ) < 0) { + int erno = errno; + + if (surface) + D_PERROR( "DirectFB/FBDev: " + "Could not set video mode (FBIOPUT_VSCREENINFO)!\n" ); + + dfb_gfxcard_unlock(); + + return errno2result( erno ); + } + + /* + * the video mode was set successfully, check if there is enough + * video ram (for buggy framebuffer drivers) + */ + + if (shared->fix.smem_len < (var.yres_virtual * + var.xres_virtual * + var.bits_per_pixel >> 3) + || (var.xres_virtual < vxres) + || (var.yres_virtual < vyres)) + { + if (surface) { + D_PERROR( "DirectFB/FBDev: " + "Could not set video mode (not enough video ram)!\n" ); + + /* restore mode */ + FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &shared->current_var ); + } + + dfb_gfxcard_unlock(); + + return DFB_INVARG; + } + + /* If surface is NULL the mode was only tested, otherwise apply changes. */ + if (surface) { + struct fb_fix_screeninfo fix; + + FBDEV_IOCTL( FBIOGET_VSCREENINFO, &var ); + + vxres = var.xres_virtual; + switch (config->buffermode) { + case DLBM_TRIPLE: + vyres = var.yres_virtual / 3; + break; + case DLBM_BACKVIDEO: + vyres = var.yres_virtual / 2; + break; + default: + vyres = var.yres_virtual; + break; + } + + format = dfb_fbdev_get_pixelformat( &var ); + if (format == DSPF_UNKNOWN) { + D_WARN( "unknown format" ); + + /* restore mode */ + FBDEV_IOCTL( FBIOPUT_VSCREENINFO, &shared->current_var ); + + dfb_gfxcard_unlock(); + + return DFB_UNSUPPORTED; + } + + if (!config) { + dfb_gfxcard_unlock(); + + return DFB_OK; + } + + if (format != config->format) { + if (DFB_BYTES_PER_PIXEL(format) == 1 || + (format == DSPF_RGB32 && config->format == DSPF_ARGB) || + (format == DSPF_RGB32 && config->format == DSPF_AiRGB) || + (format == DSPF_ARGB && config->format == DSPF_AiRGB)) + format = config->format; + } + + if (config->format == DSPF_RGB332) + dfb_fbdev_set_rgb332_palette(); + else + dfb_fbdev_set_gamma_ramp( config->format ); + + shared->current_var = var; + dfb_fbdev_var_to_mode( &var, &shared->current_mode ); + + /* invalidate original pan offset */ + shared->orig_var.xoffset = 0; + shared->orig_var.yoffset = 0; + + surface->config.size.w = vxres; + surface->config.size.h = vyres; + surface->config.format = format; + + /* To get the new pitch */ + FBDEV_IOCTL( FBIOGET_FSCREENINFO, &fix ); + + D_INFO( "FBDev/Mode: Switched to %dx%d (%dx%d) at %d bit %s (wanted %s).\n", + var.xres, var.yres, var.xres_virtual, var.yres_virtual, var.bits_per_pixel, + dfb_pixelformat_name(format), dfb_pixelformat_name(config->format) ); + + /* ++Tony: Other information (such as visual formats) will also change */ + shared->fix = fix; + + dfb_surfacemanager_adjust_heap_offset( dfb_fbdev->shared->manager, + var.yres_virtual * fix.line_length ); + + if (shared->fix.xpanstep || shared->fix.ypanstep || shared->fix.ywrapstep) + dfb_fbdev_pan( var.xoffset, var.yoffset, false ); + + dfb_gfxcard_after_set_var(); + + dfb_surface_notify( surface, + CSNF_SIZEFORMAT | CSNF_FLIP | + CSNF_VIDEO | CSNF_SYSTEM ); + } + + dfb_gfxcard_unlock(); + + return DFB_OK; +} +#endif + +/* + * parses video modes in /etc/fb.modes and stores them in dfb_fbdev->shared->modes + * (to be replaced by DirectFB's own config system + */ +static DFBResult +dfb_fbdev_read_modes( void ) +{ + FILE *fp; + char line[80],label[32],value[16]; + int geometry=0, timings=0; + int dummy; + VideoMode temp_mode; + FBDevShared *shared = dfb_fbdev->shared; + VideoMode *prev = shared->modes; + + D_DEBUG_AT( FBDev_Mode, "%s()\n", __FUNCTION__ ); + + if (!(fp = fopen("/etc/fb.modes","r"))) + return errno2result( errno ); + + while (fgets(line,79,fp)) { + if (sscanf(line, "mode \"%31[^\"]\"",label) == 1) { + memset( &temp_mode, 0, sizeof(VideoMode) ); + + geometry = 0; + timings = 0; + + while (fgets(line,79,fp) && !(strstr(line,"endmode"))) { + if (5 == sscanf(line," geometry %d %d %d %d %d", &temp_mode.xres, &temp_mode.yres, &dummy, &dummy, &temp_mode.bpp)) { + geometry = 1; + } + else if (7 == sscanf(line," timings %d %d %d %d %d %d %d", &temp_mode.pixclock, &temp_mode.left_margin, &temp_mode.right_margin, + &temp_mode.upper_margin, &temp_mode.lower_margin, &temp_mode.hsync_len, &temp_mode.vsync_len)) { + timings = 1; + } + else if (1 == sscanf(line, " hsync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.hsync_high = 1; + } + else if (1 == sscanf(line, " vsync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.vsync_high = 1; + } + else if (1 == sscanf(line, " csync %15s",value) && 0 == strcasecmp(value,"high")) { + temp_mode.csync_high = 1; + } + else if (1 == sscanf(line, " laced %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.laced = 1; + } + else if (1 == sscanf(line, " double %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.doubled = 1; + } + else if (1 == sscanf(line, " gsync %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.sync_on_green = 1; + } + else if (1 == sscanf(line, " extsync %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.external_sync = 1; + } + else if (1 == sscanf(line, " bcast %15s",value) && 0 == strcasecmp(value,"true")) { + temp_mode.broadcast = 1; + } + } + + if (geometry && timings && !dfb_fbdev_test_mode_simple(&temp_mode)) { + VideoMode *mode = SHCALLOC( shared->shmpool, 1, sizeof(VideoMode) ); + if (!mode) { + D_OOSHM(); + continue; + } + + if (!prev) + shared->modes = mode; + else + prev->next = mode; + + direct_memcpy (mode, &temp_mode, sizeof(VideoMode)); + + prev = mode; + + D_DEBUG_AT( FBDev_Mode, " +-> %16s %4dx%4d %s%s\n", label, temp_mode.xres, temp_mode.yres, + temp_mode.laced ? "interlaced " : "", temp_mode.doubled ? "doublescan" : "" ); + } + } + } + + fclose (fp); + + return DFB_OK; +} + +/* + * some fbdev drivers use the palette as gamma ramp in >8bpp modes, to have + * correct colors, the gamme ramp has to be initialized. + */ + +static u16 +dfb_fbdev_calc_gamma(int n, int max) +{ + int ret = 65535 * n / max; + return CLAMP( ret, 0, 65535 ); +} + +static DFBResult +dfb_fbdev_set_gamma_ramp( DFBSurfacePixelFormat format ) +{ + int i; + + int red_size = 0; + int green_size = 0; + int blue_size = 0; + int red_max = 0; + int green_max = 0; + int blue_max = 0; + + struct fb_cmap *cmap; + + if (!dfb_fbdev) { + D_BUG( "dfb_fbdev_set_gamma_ramp() called while dfb_fbdev == NULL!" ); + + return DFB_BUG; + } + + switch (format) { + case DSPF_ARGB1555: + case DSPF_RGB555: + case DSPF_BGR555: + red_size = 32; + green_size = 32; + blue_size = 32; + break; + case DSPF_ARGB4444: + case DSPF_RGBA4444: + case DSPF_RGB444: + case DSPF_RGB16: + red_size = 32; + green_size = 64; + blue_size = 32; + break; + case DSPF_RGB24: + case DSPF_RGB32: + case DSPF_ARGB: + red_size = 256; + green_size = 256; + blue_size = 256; + break; + default: + return DFB_OK; + } + + /* + * ++Tony: The gamma ramp must be set differently if in DirectColor, + * ie, to mimic TrueColor, index == color[index]. + */ + if (dfb_fbdev->shared->fix.visual == FB_VISUAL_DIRECTCOLOR) { + red_max = 65536 / (256/red_size); + green_max = 65536 / (256/green_size); + blue_max = 65536 / (256/blue_size); + } + else { + red_max = red_size; + green_max = green_size; + blue_max = blue_size; + } + + cmap = &dfb_fbdev->shared->current_cmap; + + /* assume green to have most weight */ + cmap->len = green_size; + + for (i = 0; i < red_size; i++) + cmap->red[i] = dfb_fbdev_calc_gamma( i, red_max ); + + for (i = 0; i < green_size; i++) + cmap->green[i] = dfb_fbdev_calc_gamma( i, green_max ); + + for (i = 0; i < blue_size; i++) + cmap->blue[i] = dfb_fbdev_calc_gamma( i, blue_max ); + + /* ++Tony: Some drivers use the upper byte, some use the lower */ + if (dfb_fbdev->shared->fix.visual == FB_VISUAL_DIRECTCOLOR) { + for (i = 0; i < red_size; i++) + cmap->red[i] |= cmap->red[i] << 8; + + for (i = 0; i < green_size; i++) + cmap->green[i] |= cmap->green[i] << 8; + + for (i = 0; i < blue_size; i++) + cmap->blue[i] |= cmap->blue[i] << 8; + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not set gamma ramp" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_set_palette( CorePalette *palette ) +{ + int i; + struct fb_cmap *cmap = &dfb_fbdev->shared->current_cmap; + + D_ASSERT( palette != NULL ); + + cmap->len = palette->num_entries <= 256 ? palette->num_entries : 256; + + for (i = 0; i < (int)cmap->len; i++) { + cmap->red[i] = palette->entries[i].r; + cmap->green[i] = palette->entries[i].g; + cmap->blue[i] = palette->entries[i].b; + cmap->transp[i] = 0xff - palette->entries[i].a; + + cmap->red[i] |= cmap->red[i] << 8; + cmap->green[i] |= cmap->green[i] << 8; + cmap->blue[i] |= cmap->blue[i] << 8; + cmap->transp[i] |= cmap->transp[i] << 8; + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: Could not set the palette!\n" ); + + return errno2result(errno); + } + + return DFB_OK; +} + +static DFBResult +dfb_fbdev_set_rgb332_palette( void ) +{ + DFBResult ret = DFB_OK; + int red_val; + int green_val; + int blue_val; + int i = 0; + FusionSHMPoolShared *pool = dfb_fbdev->shared->shmpool_data; + + struct fb_cmap cmap; + + if (!dfb_fbdev) { + D_BUG( "dfb_fbdev_set_rgb332_palette() called while dfb_fbdev == NULL!" ); + + return DFB_BUG; + } + + cmap.start = 0; + cmap.len = 256; + cmap.red = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.red) { + return D_OOSHM(); + } + cmap.green = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.green) { + ret = D_OOSHM(); + goto free_red; + } + cmap.blue = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.blue) { + ret = D_OOSHM(); + goto free_green; + } + cmap.transp = (u16*)SHMALLOC( pool, 2 * 256 ); + if (!cmap.transp) { + ret = D_OOSHM(); + goto free_blue; + } + + for (red_val = 0; red_val < 8 ; red_val++) { + for (green_val = 0; green_val < 8 ; green_val++) { + for (blue_val = 0; blue_val < 4 ; blue_val++) { + cmap.red[i] = dfb_fbdev_calc_gamma( red_val, 7 ); + cmap.green[i] = dfb_fbdev_calc_gamma( green_val, 7 ); + cmap.blue[i] = dfb_fbdev_calc_gamma( blue_val, 3 ); + cmap.transp[i] = (i ? 0x2000 : 0xffff); + i++; + } + } + } + + if (FBDEV_IOCTL( FBIOPUTCMAP, &cmap ) < 0) { + D_PERROR( "DirectFB/FBDev: " + "Could not set rgb332 palette" ); + ret = errno2result(errno); + goto free_transp; + } + + free_transp: + SHFREE( pool, cmap.transp ); + free_blue: + SHFREE( pool, cmap.blue ); + free_green: + SHFREE( pool, cmap.green ); + free_red: + SHFREE( pool, cmap.red ); + + return ret; +} + +static FusionCallHandlerResult +fbdev_ioctl_call_handler( int caller, + int call_arg, + void *call_ptr, + void *ctx, + unsigned int serial, + int *ret_val ) +{ + int ret; + const char cursoroff_str[] = "\033[?1;0;0c"; + const char blankoff_str[] = "\033[9;0]"; + + if (dfb_config->vt) { + if (!dfb_config->kd_graphics && call_arg == FBIOPUT_VSCREENINFO) + ioctl( dfb_fbdev->vt->fd, KDSETMODE, KD_GRAPHICS ); + } + + ret = ioctl( dfb_fbdev->fd, call_arg, call_ptr ); + if (ret) + ret = errno; + + if (dfb_config->vt) { + if (call_arg == FBIOPUT_VSCREENINFO) { + if (!dfb_config->kd_graphics) { + ioctl( dfb_fbdev->vt->fd, KDSETMODE, KD_TEXT ); + write( dfb_fbdev->vt->fd, cursoroff_str, strlen(cursoroff_str) ); + write( dfb_fbdev->vt->fd, blankoff_str, strlen(blankoff_str) ); + } + } + } + + *ret_val = ret; + + return FCHR_RETURN; +} + +static int +fbdev_ioctl( int request, void *arg, int arg_size ) +{ + int ret; + int erno; + void *tmp_shm = NULL; + FBDevShared *shared; + + D_ASSERT( dfb_fbdev != NULL ); + + shared = dfb_fbdev->shared; + + D_ASSERT( shared != NULL ); + + if (dfb_core_is_master( dfb_fbdev->core )) { + fbdev_ioctl_call_handler( 1, request, arg, NULL, 0, &ret ); + errno = ret; + return errno ? -1 : 0; + } + + if (arg) { + if (!fusion_is_shared( dfb_core_world(dfb_fbdev->core), arg )) { + tmp_shm = SHMALLOC( shared->shmpool, arg_size ); + if (!tmp_shm) { + errno = ENOMEM; + return -1; + } + + direct_memcpy( tmp_shm, arg, arg_size ); + } + } + + ret = fusion_call_execute( &shared->fbdev_ioctl, FCEF_NONE, + request, tmp_shm ? tmp_shm : arg, &erno ); + + if (tmp_shm) { + direct_memcpy( arg, tmp_shm, arg_size ); + SHFREE( shared->shmpool, tmp_shm ); + } + + errno = erno; + + return errno ? -1 : 0; +} + diff --git a/Source/DirectFB/systems/fbdev/fbdev.h b/Source/DirectFB/systems/fbdev/fbdev.h new file mode 100755 index 0000000..a90a76b --- /dev/null +++ b/Source/DirectFB/systems/fbdev/fbdev.h @@ -0,0 +1,142 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__FBDEV_H__ +#define __CORE__FBDEV_H__ + +#include <asm/types.h> /* Needs to be included before dfb_types.h */ + +#include <core/coretypes.h> + +#include <core/layers_internal.h> + +#include <core/system.h> + +#include <fusion/call.h> +#include <fusion/reactor.h> + +#include "agp.h" +#include "fb.h" +#include "surfacemanager.h" +#include "vt.h" + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) +#endif + + +typedef struct { + /* fbdev fixed screeninfo, contains infos about memory and type of card */ + struct fb_fix_screeninfo fix; + + VideoMode *modes; /* linked list of valid + video modes */ + VideoMode current_mode; /* current video mode */ + + struct fb_var_screeninfo current_var; /* fbdev variable screeninfo + set by DirectFB */ + struct fb_var_screeninfo orig_var; /* fbdev variable screeninfo + before DirectFB was started */ + + void *orig_cmap_memory; + void *temp_cmap_memory; + void *current_cmap_memory; + + struct fb_cmap orig_cmap; /* original palette */ + + struct fb_cmap current_cmap; /* our copy of the cmap */ + + struct fb_cmap temp_cmap; /* scratch */ + + FusionCall fbdev_ioctl; /* ioctl rpc */ + + unsigned long page_mask; /* PAGE_SIZE - 1 */ + + CoreSurfacePool *pool; + + struct { + int bus; + int dev; + int func; + } pci; /* PCI Bus ID of graphics device */ + + struct { + unsigned short vendor; /* Graphics device vendor id */ + unsigned short model; /* Graphics device model id */ + } device; + + AGPShared *agp; + + FusionSHMPoolShared *shmpool; + FusionSHMPoolShared *shmpool_data; + + CoreLayerRegionConfig config; + + SurfaceManager *manager; +} FBDevShared; + +typedef struct { + FBDevShared *shared; + + CoreDFB *core; + + /* virtual framebuffer address */ + void *framebuffer_base; + + int fd; /* file descriptor for /dev/fb */ + + VirtualTerminal *vt; + + AGPDevice *agp; +} FBDev; + +/* + * core init function, opens /dev/fb, get fbdev screeninfo + * disables font acceleration, reads mode list + */ +DFBResult dfb_fbdev_initialize( void ); +DFBResult dfb_fbdev_join( void ); + +/* + * deinitializes DirectFB fbdev stuff and restores fbdev settings + */ +DFBResult dfb_fbdev_shutdown( bool emergency ); +DFBResult dfb_fbdev_leave ( bool emergency ); + +const VideoMode *dfb_fbdev_find_mode( int width, + int height ); +DFBResult dfb_fbdev_test_mode ( const VideoMode *mode, + const CoreLayerRegionConfig *config ); +DFBResult dfb_fbdev_test_mode_simple( const VideoMode *mode ); + +DFBResult dfb_fbdev_set_mode ( const VideoMode *mode, + CoreSurface *surface, + unsigned int xoffset, + unsigned int yoffset ); + +#endif diff --git a/Source/DirectFB/systems/fbdev/fbdev_surface_pool.c b/Source/DirectFB/systems/fbdev/fbdev_surface_pool.c new file mode 100755 index 0000000..c5454a6 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/fbdev_surface_pool.c @@ -0,0 +1,423 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <asm/types.h> + +#include <config.h> + +#include <direct/debug.h> +#include <direct/mem.h> + +#include <core/surface_pool.h> + +#include <gfx/convert.h> + +#include "fbdev.h" +#include "surfacemanager.h" + +extern FBDev *dfb_fbdev; + +D_DEBUG_DOMAIN( FBDev_Surfaces, "FBDev/Surfaces", "FBDev Framebuffer Surface Pool" ); +D_DEBUG_DOMAIN( FBDev_SurfLock, "FBDev/SurfLock", "FBDev Framebuffer Surface Pool Locks" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + SurfaceManager *manager; +} FBDevPoolData; + +typedef struct { + int magic; + + CoreDFB *core; +} FBDevPoolLocalData; + +typedef struct { + int magic; + + int offset; + int pitch; + int size; + + Chunk *chunk; +} FBDevAllocationData; + +/**********************************************************************************************************************/ + +static int +fbdevPoolDataSize( void ) +{ + return sizeof(FBDevPoolData); +} + +static int +fbdevPoolLocalDataSize( void ) +{ + return sizeof(FBDevPoolLocalData); +} + +static int +fbdevAllocationDataSize( void ) +{ + return sizeof(FBDevAllocationData); +} + +static DFBResult +fbdevInitPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data, + CoreSurfacePoolDescription *ret_desc ) +{ + DFBResult ret; + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + + D_DEBUG_AT( FBDev_Surfaces, "%s()\n", __FUNCTION__ ); + + D_ASSERT( core != NULL ); + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( data != NULL ); + D_ASSERT( local != NULL ); + D_ASSERT( ret_desc != NULL ); + + ret = dfb_surfacemanager_create( core, dfb_fbdev->shared->fix.smem_len, &data->manager ); + if (ret) + return ret; + + ret_desc->caps = CSPCAPS_PHYSICAL | CSPCAPS_VIRTUAL; + ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; + ret_desc->access[CSAID_GPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; + ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_EXTERNAL; + ret_desc->priority = CSPP_DEFAULT; + + /* For hardware layers */ + ret_desc->access[CSAID_LAYER0] = CSAF_READ; + ret_desc->access[CSAID_LAYER1] = CSAF_READ; + ret_desc->access[CSAID_LAYER2] = CSAF_READ; + ret_desc->access[CSAID_LAYER3] = CSAF_READ; + ret_desc->access[CSAID_LAYER4] = CSAF_READ; + ret_desc->access[CSAID_LAYER5] = CSAF_READ; + ret_desc->access[CSAID_LAYER6] = CSAF_READ; + ret_desc->access[CSAID_LAYER7] = CSAF_READ; + + snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Frame Buffer Memory" ); + + local->core = core; + + D_MAGIC_SET( data, FBDevPoolData ); + D_MAGIC_SET( local, FBDevPoolLocalData ); + + + D_ASSERT( dfb_fbdev != NULL ); + D_ASSERT( dfb_fbdev->shared != NULL ); + + dfb_fbdev->shared->manager = data->manager; + + return DFB_OK; +} + +static DFBResult +fbdevJoinPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data ) +{ + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + + D_DEBUG_AT( FBDev_Surfaces, "%s()\n", __FUNCTION__ ); + + D_ASSERT( core != NULL ); + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_ASSERT( local != NULL ); + + (void) data; + + local->core = core; + + D_MAGIC_SET( local, FBDevPoolLocalData ); + + return DFB_OK; +} + +static DFBResult +fbdevDestroyPool( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ) +{ + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + + D_DEBUG_AT( FBDev_Surfaces, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_MAGIC_ASSERT( local, FBDevPoolLocalData ); + + dfb_surfacemanager_destroy( data->manager ); + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( local ); + + return DFB_OK; +} + +static DFBResult +fbdevLeavePool( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ) +{ + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + + D_DEBUG_AT( FBDev_Surfaces, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_MAGIC_ASSERT( local, FBDevPoolLocalData ); + + (void) data; + + D_MAGIC_CLEAR( local ); + + return DFB_OK; +} + +static DFBResult +fbdevTestConfig( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + const CoreSurfaceConfig *config ) +{ + DFBResult ret; + CoreSurface *surface; + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + + D_DEBUG_AT( FBDev_Surfaces, "%s( %p )\n", __FUNCTION__, buffer ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_MAGIC_ASSERT( local, FBDevPoolLocalData ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + if ((surface->type & CSTF_LAYER) && surface->resource_id == DLID_PRIMARY) + return DFB_OK; + + ret = dfb_surfacemanager_allocate( local->core, data->manager, buffer, NULL, NULL ); + + D_DEBUG_AT( FBDev_Surfaces, " -> %s\n", DirectFBErrorString(ret) ); + + return ret; +} + +static DFBResult +fbdevAllocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + DFBResult ret; + CoreSurface *surface; + FBDevPoolData *data = pool_data; + FBDevPoolLocalData *local = pool_local; + FBDevAllocationData *alloc = alloc_data; + + D_DEBUG_AT( FBDev_Surfaces, "%s( %p )\n", __FUNCTION__, buffer ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_MAGIC_ASSERT( local, FBDevPoolLocalData ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + if ((surface->type & CSTF_LAYER) && surface->resource_id == DLID_PRIMARY) { + FBDevShared *shared = dfb_fbdev->shared; + int index = dfb_surface_buffer_index( buffer ); + + D_DEBUG_AT( FBDev_Surfaces, " -> primary layer buffer (index %d)\n", index ); + + if (index == 0) { + const VideoMode *highest; + /* FIXME: this should use source.w/source.h from layer region config! */ + unsigned int width = surface->config.size.w; + unsigned int height = surface->config.size.h; + + D_INFO( "FBDev/Mode: Setting %dx%d %s\n", width, height, dfb_pixelformat_name(surface->config.format) ); + + highest = dfb_fbdev_find_mode( width, height ); + if (!highest) + return DFB_UNSUPPORTED; + + ret = dfb_fbdev_set_mode( highest, surface, 0, 0 ); + if (ret) + return ret; + } + + alloc->pitch = shared->fix.line_length; + alloc->size = surface->config.size.h * alloc->pitch; + alloc->offset = index * alloc->size; + + D_INFO( "FBDev/Surface: Allocated %dx%d %d bit %s buffer (index %d) at offset %d and pitch %d.\n", + surface->config.size.w, surface->config.size.h, shared->current_var.bits_per_pixel, + dfb_pixelformat_name(buffer->format), index, alloc->offset, alloc->pitch ); + } + else { + Chunk *chunk; + + ret = dfb_surfacemanager_allocate( local->core, data->manager, buffer, allocation, &chunk ); + if (ret) + return ret; + + D_MAGIC_ASSERT( chunk, Chunk ); + + alloc->offset = chunk->offset; + alloc->pitch = chunk->pitch; + alloc->size = chunk->length; + + alloc->chunk = chunk; + } + + D_DEBUG_AT( FBDev_Surfaces, " -> offset %d, pitch %d, size %d\n", alloc->offset, alloc->pitch, alloc->size ); + + allocation->size = alloc->size; + allocation->offset = alloc->offset; + + D_MAGIC_SET( alloc, FBDevAllocationData ); + + return DFB_OK; +} + +static DFBResult +fbdevDeallocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + FBDevPoolData *data = pool_data; + FBDevAllocationData *alloc = alloc_data; + + D_DEBUG_AT( FBDev_Surfaces, "%s( %p )\n", __FUNCTION__, buffer ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( data, FBDevPoolData ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( alloc, FBDevAllocationData ); + + if (alloc->chunk) + dfb_surfacemanager_deallocate( data->manager, alloc->chunk ); + + D_MAGIC_CLEAR( alloc ); + + return DFB_OK; +} + +static DFBResult +fbdevLock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + FBDevAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( alloc, FBDevAllocationData ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + D_DEBUG_AT( FBDev_SurfLock, "%s( %p )\n", __FUNCTION__, lock->buffer ); + + lock->pitch = alloc->pitch; + lock->offset = alloc->offset; + lock->addr = dfb_fbdev->framebuffer_base + alloc->offset; + lock->phys = dfb_fbdev->shared->fix.smem_start + alloc->offset; + + D_DEBUG_AT( FBDev_SurfLock, " -> offset %lu, pitch %d, addr %p, phys 0x%08lx\n", + lock->offset, lock->pitch, lock->addr, lock->phys ); + + return DFB_OK; +} + +static DFBResult +fbdevUnlock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + FBDevAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( alloc, FBDevAllocationData ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + D_DEBUG_AT( FBDev_SurfLock, "%s( %p )\n", __FUNCTION__, lock->buffer ); + + (void) alloc; + + return DFB_OK; +} + +const SurfacePoolFuncs fbdevSurfacePoolFuncs = { + .PoolDataSize = fbdevPoolDataSize, + .PoolLocalDataSize = fbdevPoolLocalDataSize, + .AllocationDataSize = fbdevAllocationDataSize, + + .InitPool = fbdevInitPool, + .JoinPool = fbdevJoinPool, + .DestroyPool = fbdevDestroyPool, + .LeavePool = fbdevLeavePool, + + .TestConfig = fbdevTestConfig, + .AllocateBuffer = fbdevAllocateBuffer, + .DeallocateBuffer = fbdevDeallocateBuffer, + + .Lock = fbdevLock, + .Unlock = fbdevUnlock, +}; + diff --git a/Source/DirectFB/systems/fbdev/surfacemanager.c b/Source/DirectFB/systems/fbdev/surfacemanager.c new file mode 100755 index 0000000..811288b --- /dev/null +++ b/Source/DirectFB/systems/fbdev/surfacemanager.c @@ -0,0 +1,617 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <config.h> + +#include <fusion/shmalloc.h> + +#include <directfb.h> +#include <directfb_util.h> + +#include <core/core.h> + +#include <core/gfxcard.h> +#include <core/surface.h> +#include <core/surface_buffer.h> + +#include <direct/debug.h> +#include <direct/messages.h> +#include <direct/util.h> + +#include <gfx/convert.h> + +#include "surfacemanager.h" + +D_DEBUG_DOMAIN( SurfMan, "SurfaceManager", "DirectFB Surface Manager" ); + + +static Chunk *split_chunk ( SurfaceManager *manager, + Chunk *chunk, + int length ); + +static Chunk *free_chunk ( SurfaceManager *manager, + Chunk *chunk ); + +static Chunk *occupy_chunk( SurfaceManager *manager, + Chunk *chunk, + CoreSurfaceAllocation *allocation, + int length, + int pitch ); + + +DFBResult +dfb_surfacemanager_create( CoreDFB *core, + unsigned int length, + SurfaceManager **ret_manager ) +{ + FusionSHMPoolShared *pool; + SurfaceManager *manager; + Chunk *chunk; + + D_DEBUG_AT( SurfMan, "%s( %p, %d )\n", __FUNCTION__, core, length ); + + D_ASSERT( core != NULL ); + D_ASSERT( ret_manager != NULL ); + + pool = dfb_core_shmpool( core ); + + manager = SHCALLOC( pool, 1, sizeof(SurfaceManager) ); + if (!manager) + return D_OOSHM(); + + chunk = SHCALLOC( pool, 1, sizeof(Chunk) ); + if (!chunk) { + D_OOSHM(); + SHFREE( pool, manager ); + return DFB_NOSHAREDMEMORY; + } + + manager->shmpool = pool; + manager->chunks = chunk; + manager->offset = 0; + manager->length = length; + manager->avail = manager->length - manager->offset; + + D_MAGIC_SET( manager, SurfaceManager ); + + chunk->offset = manager->offset; + chunk->length = manager->avail; + + D_MAGIC_SET( chunk, Chunk ); + + D_DEBUG_AT( SurfMan, " -> %p\n", manager ); + + *ret_manager = manager; + + return DFB_OK; +} + +void +dfb_surfacemanager_destroy( SurfaceManager *manager ) +{ + Chunk *chunk; + void *next; + + D_DEBUG_AT( SurfMan, "%s( %p )\n", __FUNCTION__, manager ); + + D_MAGIC_ASSERT( manager, SurfaceManager ); + + /* Deallocate all video chunks. */ + chunk = manager->chunks; + while (chunk) { + next = chunk->next; + + D_MAGIC_CLEAR( chunk ); + + SHFREE( manager->shmpool, chunk ); + + chunk = next; + } + + D_MAGIC_CLEAR( manager ); + + /* Deallocate manager struct. */ + SHFREE( manager->shmpool, manager ); +} + +DFBResult dfb_surfacemanager_adjust_heap_offset( SurfaceManager *manager, + int offset ) +{ + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_ASSERT( offset >= 0 ); + + D_DEBUG_AT( SurfMan, "%s( %p, %d )\n", __FUNCTION__, manager, offset ); + +/*FIXME_SC_2 if (manager->limits.surface_byteoffset_alignment > 1) { + offset += manager->limits.surface_byteoffset_alignment - 1; + offset -= offset % manager->limits.surface_byteoffset_alignment; + } +*/ + /* + * Adjust the offset of the heap. + */ + if (manager->chunks->buffer == NULL) { + /* first chunk is free */ + if (offset <= manager->chunks->offset + manager->chunks->length) { + /* ok, just recalculate offset and length */ + manager->chunks->length = manager->chunks->offset + + manager->chunks->length - offset; + manager->chunks->offset = offset; + } + else { + D_WARN("unable to adjust heap offset"); + /* more space needed than free at the beginning */ + /* TODO: move/destroy instances */ + } + } + else { + D_WARN("unable to adjust heap offset"); + /* very rare case that the first chunk is occupied */ + /* TODO: move/destroy instances */ + } + + manager->avail -= offset - manager->offset; + manager->offset = offset; + + return DFB_OK; +} + +/** public functions NOT locking the surfacemanger theirself, + to be called between lock/unlock of surfacemanager **/ + +DFBResult dfb_surfacemanager_allocate( CoreDFB *core, + SurfaceManager *manager, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + Chunk **ret_chunk ) +{ + int pitch; + int length; + Chunk *c; + CoreGraphicsDevice *device; + + Chunk *best_free = NULL; + + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( buffer->surface, CoreSurface ); + + if (ret_chunk) + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + else + D_ASSUME( allocation == NULL ); + + D_DEBUG_AT( SurfMan, "%s( %p ) <- %dx%d %s\n", __FUNCTION__, buffer, + buffer->surface->config.size.w, buffer->surface->config.size.h, + dfb_pixelformat_name( buffer->surface->config.format ) ); + + if (manager->suspended) + return DFB_SUSPENDED; + + /* FIXME: Only one global device at the moment. */ + device = dfb_core_get_part( core, DFCP_GRAPHICS ); + D_ASSERT( device != NULL ); + + dfb_gfxcard_calc_buffer_size( device, buffer, &pitch, &length ); + + D_DEBUG_AT( SurfMan, " -> pitch %d, length %d\n", pitch, length ); + + if (manager->avail < length) + return DFB_TEMPUNAVAIL; + + /* examine chunks */ + c = manager->chunks; + D_MAGIC_ASSERT( c, Chunk ); + + /* FIXME_SC_2 Workaround creation happening before graphics driver initialization. */ + if (!c->next) { + int length = dfb_gfxcard_memory_length(); + + if (c->length != length - manager->offset) { + D_WARN( "workaround" ); + + manager->length = length; + manager->avail = length - manager->offset; + + c->length = length - manager->offset; + } + } + + while (c) { + D_MAGIC_ASSERT( c, Chunk ); + + if (!c->buffer && c->length >= length) { + /* NULL means check only. */ + if (!ret_chunk) + return DFB_OK; + + /* found a nice place to chill */ + if (!best_free || best_free->length > c->length) + /* first found or better one? */ + best_free = c; + + if (c->length == length) + break; + } + + c = c->next; + } + + /* if we found a place */ + if (best_free) { + D_DEBUG_AT( SurfMan, " -> found free (%d)\n", best_free->length ); + + /* NULL means check only. */ + if (ret_chunk) + *ret_chunk = occupy_chunk( manager, best_free, allocation, length, pitch ); + + return DFB_OK; + } + + D_DEBUG_AT( SurfMan, " -> failed (%d/%d avail)\n", manager->avail, manager->length ); + + /* no luck */ + return DFB_NOVIDEOMEMORY; +} + +DFBResult dfb_surfacemanager_displace( CoreDFB *core, + SurfaceManager *manager, + CoreSurfaceBuffer *buffer ) +{ + int length; + Chunk *multi_start = NULL; + int multi_size = 0; + int multi_tsize = 0; + int multi_count = 0; + Chunk *bestm_start = NULL; + int bestm_count = 0; + int bestm_size = 0; + int min_toleration; + Chunk *chunk; + CoreGraphicsDevice *device; + CoreSurfaceAllocation *smallest = NULL; + + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( buffer->surface, CoreSurface ); + + D_DEBUG_AT( SurfMan, "%s( %p ) <- %dx%d %s\n", __FUNCTION__, buffer, + buffer->surface->config.size.w, buffer->surface->config.size.h, + dfb_pixelformat_name( buffer->surface->config.format ) ); + + /* FIXME: Only one global device at the moment. */ + device = dfb_core_get_part( core, DFCP_GRAPHICS ); + D_ASSERT( device != NULL ); + + dfb_gfxcard_calc_buffer_size( dfb_core_get_part( core, DFCP_GRAPHICS ), buffer, NULL, &length ); + + min_toleration = manager->min_toleration/8 + 2; + + D_DEBUG_AT( SurfMan, " -> %7d required, min toleration %d\n", length, min_toleration ); + + chunk = manager->chunks; + while (chunk) { + CoreSurfaceAllocation *allocation; + + D_MAGIC_ASSERT( chunk, Chunk ); + + allocation = chunk->allocation; + if (allocation) { + CoreSurfaceBuffer *other; + int size; + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_ASSERT( chunk->buffer == allocation->buffer ); + D_ASSERT( chunk->length >= allocation->size ); + + other = allocation->buffer; + D_MAGIC_ASSERT( other, CoreSurfaceBuffer ); + + if (other->locked) { + D_DEBUG_AT( SurfMan, " ++ %7d locked %dx\n", allocation->size, other->locked ); + goto next_reset; + } + + if (other->policy > buffer->policy) { + D_DEBUG_AT( SurfMan, " ++ %7d policy %d > %d\n", allocation->size, other->policy, buffer->policy ); + goto next_reset; + } + + if (other->policy == CSP_VIDEOONLY) { + D_DEBUG_AT( SurfMan, " ++ %7d policy videoonly\n", allocation->size ); + goto next_reset; + } + + chunk->tolerations++; + if (chunk->tolerations > 0xff) + chunk->tolerations = 0xff; + + if (other->policy == buffer->policy && chunk->tolerations < min_toleration) { + D_DEBUG_AT( SurfMan, " ++ %7d tolerations %d/%d\n", + allocation->size, chunk->tolerations, min_toleration ); + goto next_reset; + } + + size = allocation->size; + + if (chunk->prev && !chunk->prev->allocation) + size += chunk->prev->length; + + if (chunk->next && !chunk->next->allocation) + size += chunk->next->length; + + if (size >= length) { + if (!smallest || smallest->size > allocation->size) { + D_DEBUG_AT( SurfMan, " => %7d [%d] < %d, tolerations %d\n", + allocation->size, size, smallest ? smallest->size : 0, chunk->tolerations ); + + smallest = allocation; + } + else + D_DEBUG_AT( SurfMan, " -> %7d [%d] > %d\n", allocation->size, size, smallest->size ); + } + else + D_DEBUG_AT( SurfMan, " -> %7d [%d]\n", allocation->size, size ); + } + else + D_DEBUG_AT( SurfMan, " - %7d free\n", chunk->length ); + + + if (!smallest) { + if (!multi_start) { + multi_start = chunk; + multi_tsize = chunk->length; + multi_size = chunk->allocation ? chunk->length : 0; + multi_count = chunk->allocation ? 1 : 0; + } + else { + multi_tsize += chunk->length; + multi_size += chunk->allocation ? chunk->length : 0; + multi_count += chunk->allocation ? 1 : 0; + + while (multi_tsize >= length && multi_count > 1) { + if (!bestm_start || bestm_size > multi_size * multi_count / bestm_count) { + D_DEBUG_AT( SurfMan, " =====> %7d, %7d %2d used [%7d %2d]\n", + multi_tsize, multi_size, multi_count, bestm_size, bestm_count ); + + bestm_size = multi_size; + bestm_start = multi_start; + bestm_count = multi_count; + } + else + D_DEBUG_AT( SurfMan, " -----> %7d, %7d %2d used\n", + multi_tsize, multi_size, multi_count ); + + if (multi_count <= 2) + break; + + if (!multi_start->allocation) { + multi_tsize -= multi_start->length; + multi_start = multi_start->next; + } + + D_ASSUME( multi_start->allocation != NULL ); + + multi_tsize -= multi_start->length; + multi_size -= multi_start->allocation ? multi_start->length : 0; + multi_count -= multi_start->allocation ? 1 : 0; + multi_start = multi_start->next; + } + } + } + + chunk = chunk->next; + + continue; + + +next_reset: + multi_start = NULL; + + chunk = chunk->next; + } + + if (smallest) { + D_MAGIC_ASSERT( smallest, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( smallest->buffer, CoreSurfaceBuffer ); + + smallest->flags |= CSALF_MUCKOUT; + + D_DEBUG_AT( SurfMan, " -> offset %lu, size %d\n", smallest->offset, smallest->size ); + + return DFB_OK; + } + + if (bestm_start) { + chunk = bestm_start; + + while (bestm_count) { + CoreSurfaceAllocation *allocation = chunk->allocation; + + if (allocation) { + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( allocation->buffer, CoreSurfaceBuffer ); + + allocation->flags |= CSALF_MUCKOUT; + + bestm_count--; + } + + D_DEBUG_AT( SurfMan, " ---> offset %d, length %d\n", chunk->offset, chunk->length ); + + chunk = chunk->next; + } + + return DFB_OK; + } + + return DFB_NOVIDEOMEMORY; +} + +DFBResult dfb_surfacemanager_deallocate( SurfaceManager *manager, + Chunk *chunk ) +{ + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_MAGIC_ASSERT( chunk, Chunk ); + + buffer = chunk->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( buffer->surface, CoreSurface ); + + D_DEBUG_AT( SurfMan, "%s( %p ) <- %dx%d %s\n", __FUNCTION__, buffer, + buffer->surface->config.size.w, buffer->surface->config.size.h, + dfb_pixelformat_name( buffer->surface->config.format ) ); + + free_chunk( manager, chunk ); + + return DFB_OK; +} + +/** internal functions NOT locking the surfacemanager **/ + +static Chunk * +split_chunk( SurfaceManager *manager, Chunk *c, int length ) +{ + Chunk *newchunk; + + D_MAGIC_ASSERT( c, Chunk ); + + if (c->length == length) /* does not need be splitted */ + return c; + + newchunk = (Chunk*) SHCALLOC( manager->shmpool, 1, sizeof(Chunk) ); + if (!newchunk) { + D_OOSHM(); + return NULL; + } + + /* calculate offsets and lengths of resulting chunks */ + newchunk->offset = c->offset + c->length - length; + newchunk->length = length; + c->length -= newchunk->length; + + /* insert newchunk after chunk c */ + newchunk->prev = c; + newchunk->next = c->next; + if (c->next) + c->next->prev = newchunk; + c->next = newchunk; + + D_MAGIC_SET( newchunk, Chunk ); + + return newchunk; +} + +static Chunk * +free_chunk( SurfaceManager *manager, Chunk *chunk ) +{ + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_MAGIC_ASSERT( chunk, Chunk ); + + if (!chunk->buffer) { + D_BUG( "freeing free chunk" ); + return chunk; + } + else { + D_DEBUG_AT( SurfMan, "Deallocating %d bytes at offset %d.\n", chunk->length, chunk->offset ); + } + + if (chunk->buffer->policy == CSP_VIDEOONLY) + manager->avail += chunk->length; + + chunk->allocation = NULL; + chunk->buffer = NULL; + + manager->min_toleration--; + + if (chunk->prev && !chunk->prev->buffer) { + Chunk *prev = chunk->prev; + + //D_DEBUG_AT( SurfMan, " -> merging with previous chunk at %d\n", prev->offset ); + + prev->length += chunk->length; + + prev->next = chunk->next; + if (prev->next) + prev->next->prev = prev; + + //D_DEBUG_AT( SurfMan, " -> freeing %p (prev %p, next %p)\n", chunk, chunk->prev, chunk->next); + + D_MAGIC_CLEAR( chunk ); + + SHFREE( manager->shmpool, chunk ); + chunk = prev; + } + + if (chunk->next && !chunk->next->buffer) { + Chunk *next = chunk->next; + + //D_DEBUG_AT( SurfMan, " -> merging with next chunk at %d\n", next->offset ); + + chunk->length += next->length; + + chunk->next = next->next; + if (chunk->next) + chunk->next->prev = chunk; + + D_MAGIC_CLEAR( next ); + + SHFREE( manager->shmpool, next ); + } + + return chunk; +} + +static Chunk * +occupy_chunk( SurfaceManager *manager, Chunk *chunk, CoreSurfaceAllocation *allocation, int length, int pitch ) +{ + D_MAGIC_ASSERT( manager, SurfaceManager ); + D_MAGIC_ASSERT( chunk, Chunk ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( allocation->buffer, CoreSurfaceBuffer ); + + if (allocation->buffer->policy == CSP_VIDEOONLY) + manager->avail -= length; + + chunk = split_chunk( manager, chunk, length ); + if (!chunk) + return NULL; + + D_DEBUG_AT( SurfMan, "Allocating %d bytes at offset %d.\n", chunk->length, chunk->offset ); + + chunk->allocation = allocation; + chunk->buffer = allocation->buffer; + chunk->pitch = pitch; + + manager->min_toleration++; + + return chunk; +} + diff --git a/Source/DirectFB/systems/fbdev/surfacemanager.h b/Source/DirectFB/systems/fbdev/surfacemanager.h new file mode 100755 index 0000000..f7812d1 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/surfacemanager.h @@ -0,0 +1,117 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __SURFACEMANAGER_H__ +#define __SURFACEMANAGER_H__ + +#include <directfb.h> + +#include <core/coretypes.h> + +typedef struct _SurfaceManager SurfaceManager; +typedef struct _Chunk Chunk; + +/* + * initially there is one big free chunk, + * chunks are splitted into a free and an occupied chunk if memory is allocated, + * two chunks are merged to one free chunk if memory is deallocated + */ +struct _Chunk { + int magic; + + int offset; /* offset in memory, + is greater or equal to the heap offset */ + int length; /* length of this chunk in bytes */ + + int pitch; + + CoreSurfaceBuffer *buffer; /* pointer to surface buffer occupying + this chunk, or NULL if chunk is free */ + CoreSurfaceAllocation *allocation; + + int tolerations; /* number of times this chunk was scanned + occupied, resetted in assure_video */ + + Chunk *prev; + Chunk *next; +}; + +struct _SurfaceManager { + int magic; + + FusionSHMPoolShared *shmpool; + + Chunk *chunks; + + int offset; + int length; /* length of the heap in bytes */ + int avail; /* amount of available memory in bytes */ + + int min_toleration; + + bool suspended; +}; + + +DFBResult dfb_surfacemanager_create ( CoreDFB *core, + unsigned int length, + SurfaceManager **ret_manager ); + +void dfb_surfacemanager_destroy( SurfaceManager *manager ); + +/* + * adjust the offset within the framebuffer for surface storage, + * needs to be called after a resolution switch + */ +DFBResult dfb_surfacemanager_adjust_heap_offset( SurfaceManager *manager, + int offset ); + +/* + * finds and allocates one for the surface or fails, + * after success the video health is CSH_RESTORE. + * NOTE: this does not notify the listeners + */ +DFBResult dfb_surfacemanager_allocate( CoreDFB *core, + SurfaceManager *manager, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + Chunk **ret_chunk ); + +DFBResult dfb_surfacemanager_displace( CoreDFB *core, + SurfaceManager *manager, + CoreSurfaceBuffer *buffer ); + +/* + * sets the video health to CSH_INVALID frees the chunk and + * notifies the listeners + */ +DFBResult dfb_surfacemanager_deallocate( SurfaceManager *manager, + Chunk *chunk ); + +#endif + diff --git a/Source/DirectFB/systems/fbdev/vt.c b/Source/DirectFB/systems/fbdev/vt.c new file mode 100755 index 0000000..02bad77 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/vt.c @@ -0,0 +1,675 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <config.h> + +#include <asm/types.h> /* Needs to be included before dfb_types.h */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/vt.h> +#include <sys/kd.h> +#include <errno.h> +#include <pthread.h> + +#include <directfb.h> + +#include <misc/conf.h> +#include <misc/util.h> + +#include <direct/debug.h> +#include <direct/mem.h> +#include <direct/messages.h> +#include <direct/thread.h> +#include <direct/util.h> + +#include <core/core.h> +#include <core/coredefs.h> +#include <core/coretypes.h> +#include <core/gfxcard.h> + +#include "fbdev.h" +#include "fb.h" +#include "vt.h" + +D_DEBUG_DOMAIN( VT, "FBDev/VT", "FBDev System Module VT Handling" ); + +/* + * FIXME: the following looks like a bad hack. + * + * SIGUNUSED is no longer unused, but is defined for backwards compatibility. + * sparc, mips and alpha signal.h however do not define SIGUNUSED. + */ + +#ifdef SIGUNUSED + #define SIG_SWITCH_FROM (SIGUNUSED + 10) + #define SIG_SWITCH_TO (SIGUNUSED + 11) +#else + #define SIG_SWITCH_FROM (31 + 10) + #define SIG_SWITCH_TO (31 + 11) +#endif + +#ifndef SI_KERNEL +/* glibc 2.1.x doesn't have this in /usr/include/bits/siginfo.h */ + #define SI_KERNEL 0x80 +#endif + + +extern FBDev *dfb_fbdev; + +static VirtualTerminal *dfb_vt = NULL; + +static DFBResult vt_init_switching( void ); +static int vt_get_fb( int vt ); +static void vt_set_fb( int vt, int fb ); +static void *vt_thread( DirectThread *thread, void *arg ); + +static void vt_start_flushing( void ); +static void vt_stop_flushing( void ); +static void *vt_flush_thread( DirectThread *thread, void *arg ); + +DFBResult +dfb_vt_initialize( void ) +{ + DFBResult ret; + struct vt_stat vs; + + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + dfb_vt = D_CALLOC( 1, sizeof(VirtualTerminal) ); + if (!dfb_vt) + return D_OOM(); + + setsid(); + dfb_vt->fd0 = open( "/dev/tty0", O_RDONLY | O_NOCTTY ); + if (dfb_vt->fd0 < 0) { + if (errno == ENOENT) { + dfb_vt->fd0 = open( "/dev/vc/0", O_RDONLY | O_NOCTTY ); + if (dfb_vt->fd0 < 0) { + if (errno == ENOENT) { + D_PERROR( "DirectFB/core/vt: Couldn't open " + "neither `/dev/tty0' nor `/dev/vc/0'!\n" ); + } + else { + D_PERROR( "DirectFB/core/vt: " + "Error opening `/dev/vc/0'!\n" ); + } + + D_FREE( dfb_vt ); + dfb_vt = NULL; + + return DFB_INIT; + } + } + else { + D_PERROR( "DirectFB/core/vt: Error opening `/dev/tty0'!\n"); + + D_FREE( dfb_vt ); + dfb_vt = NULL; + + return DFB_INIT; + } + } + + if (ioctl( dfb_vt->fd0, VT_GETSTATE, &vs ) < 0) { + D_PERROR( "DirectFB/core/vt: VT_GETSTATE failed!\n" ); + close( dfb_vt->fd0 ); + D_FREE( dfb_vt ); + dfb_vt = NULL; + return DFB_INIT; + } + + dfb_vt->prev = vs.v_active; + + + if (!dfb_config->vt_switch) { + if (dfb_config->vt_num != -1) + dfb_vt->num = dfb_config->vt_num; + else + dfb_vt->num = dfb_vt->prev; + + /* move vt to framebuffer */ + dfb_vt->old_fb = vt_get_fb( dfb_vt->num ); + vt_set_fb( dfb_vt->num, -1 ); + } + else { + if (dfb_config->vt_num == -1) { + int n; + + n = ioctl( dfb_vt->fd0, VT_OPENQRY, &dfb_vt->num ); + if (n < 0 || dfb_vt->num == -1) { + D_PERROR( "DirectFB/core/vt: Cannot allocate VT!\n" ); + close( dfb_vt->fd0 ); + D_FREE( dfb_vt ); + dfb_vt = NULL; + return DFB_INIT; + } + } + else { + dfb_vt->num = dfb_config->vt_num; + } + + /* move vt to framebuffer */ + dfb_vt->old_fb = vt_get_fb( dfb_vt->num ); + vt_set_fb( dfb_vt->num, -1 ); + + /* switch to vt */ + while (ioctl( dfb_vt->fd0, VT_ACTIVATE, dfb_vt->num ) < 0) { + if (errno == EINTR) + continue; + D_PERROR( "DirectFB/core/vt: VT_ACTIVATE failed!\n" ); + close( dfb_vt->fd0 ); + D_FREE( dfb_vt ); + dfb_vt = NULL; + return DFB_INIT; + } + + while (ioctl( dfb_vt->fd0, VT_WAITACTIVE, dfb_vt->num ) < 0) { + if (errno == EINTR) + continue; + D_PERROR( "DirectFB/core/vt: VT_WAITACTIVE failed!\n" ); + close( dfb_vt->fd0 ); + D_FREE( dfb_vt ); + dfb_vt = NULL; + return DFB_INIT; + } + + usleep( 40000 ); + } + + ret = vt_init_switching(); + if (ret) { + if (dfb_config->vt_switch) { + D_DEBUG_AT( VT, " -> switching back...\n" ); + ioctl( dfb_vt->fd0, VT_ACTIVATE, dfb_vt->prev ); + ioctl( dfb_vt->fd0, VT_WAITACTIVE, dfb_vt->prev ); + D_DEBUG_AT( VT, " -> ...switched back\n" ); + ioctl( dfb_vt->fd0, VT_DISALLOCATE, dfb_vt->num ); + } + + close( dfb_vt->fd0 ); + D_FREE( dfb_vt ); + dfb_vt = NULL; + return ret; + } + + vt_start_flushing(); + + dfb_fbdev->vt = dfb_vt; + + return DFB_OK; +} + +DFBResult +dfb_vt_join( void ) +{ + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + dfb_vt_detach( true ); + + return DFB_OK; +} + +DFBResult +dfb_vt_shutdown( bool emergency ) +{ + const char cursoron_str[] = "\033[?0;0;0c"; + const char blankon_str[] = "\033[9;10]"; + + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + if (!dfb_vt) + return DFB_OK; + + vt_stop_flushing(); + + if (dfb_config->vt_switching) { + if (ioctl( dfb_vt->fd, VT_SETMODE, &dfb_vt->vt_mode ) < 0) + D_PERROR( "DirectFB/fbdev/vt: Unable to restore VT mode!!!\n" ); + + sigaction( SIG_SWITCH_FROM, &dfb_vt->sig_usr1, NULL ); + sigaction( SIG_SWITCH_TO, &dfb_vt->sig_usr2, NULL ); + + direct_thread_cancel( dfb_vt->thread ); + direct_thread_join( dfb_vt->thread ); + direct_thread_destroy( dfb_vt->thread ); + + pthread_mutex_destroy( &dfb_vt->lock ); + pthread_cond_destroy( &dfb_vt->wait ); + } + + if (dfb_config->kd_graphics) { + if (ioctl( dfb_vt->fd, KDSETMODE, KD_TEXT ) < 0) + D_PERROR( "DirectFB/fbdev/vt: KD_TEXT failed!\n" ); + } + else { + write( dfb_vt->fd, blankon_str, sizeof(blankon_str) ); + } + write( dfb_vt->fd, cursoron_str, sizeof(cursoron_str) ); + + if (tcsetattr( dfb_vt->fd, TCSAFLUSH, &dfb_vt->old_ts ) < 0) + D_PERROR("DirectFB/fbdev/vt: tcsetattr for original values failed!\n"); + + if (ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ) < 0) + D_PERROR( "DirectFB/fbdev/vt: K_XLATE failed!\n" ); + + if (dfb_config->vt_switch) { + D_DEBUG_AT( VT, " -> switching back...\n" ); + + if (ioctl( dfb_vt->fd0, VT_ACTIVATE, dfb_vt->prev ) < 0) + D_PERROR( "DirectFB/core/vt: VT_ACTIVATE" ); + + if (ioctl( dfb_vt->fd0, VT_WAITACTIVE, dfb_vt->prev ) < 0) + D_PERROR( "DirectFB/core/vt: VT_WAITACTIVE" ); + + D_DEBUG_AT( VT, " -> switched back...\n" ); + + usleep( 40000 ); + + /* restore con2fbmap */ + vt_set_fb( dfb_vt->num, dfb_vt->old_fb ); + + if (close( dfb_vt->fd ) < 0) + D_PERROR( "DirectFB/core/vt: Unable to " + "close file descriptor of allocated VT!\n" ); + + if (ioctl( dfb_vt->fd0, VT_DISALLOCATE, dfb_vt->num ) < 0) + D_PERROR( "DirectFB/core/vt: Unable to disallocate VT!\n" ); + } + else { + /* restore con2fbmap */ + vt_set_fb( dfb_vt->num, dfb_vt->old_fb ); + + if (close( dfb_vt->fd ) < 0) + D_PERROR( "DirectFB/core/vt: Unable to " + "close file descriptor of current VT!\n" ); + } + + if (close( dfb_vt->fd0 ) < 0) + D_PERROR( "DirectFB/core/vt: Unable to " + "close file descriptor of tty0!\n" ); + + D_FREE( dfb_vt ); + dfb_vt = dfb_fbdev->vt = NULL; + + return DFB_OK; +} + +DFBResult +dfb_vt_leave( bool emergency ) +{ + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + return DFB_OK; +} + +DFBResult +dfb_vt_detach( bool force ) +{ + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + if (dfb_config->vt_switch || force) { + int fd; + struct vt_stat vt_state; + + fd = open( "/dev/tty", O_RDONLY | O_NOCTTY ); + if (fd < 0) { + if (errno == ENXIO) + return DFB_OK; + + D_PERROR( "DirectFB/VT: Opening /dev/tty failed!\n" ); + return errno2result( errno ); + } + + if (ioctl( fd, VT_GETSTATE, &vt_state )) { + close( fd ); + return DFB_OK; + } + + if (ioctl( fd, TIOCNOTTY )) { + D_PERROR( "DirectFB/VT: TIOCNOTTY on /dev/tty failed\n" ); + close( fd ); + return errno2result( errno ); + } + + close( fd ); + } + + return DFB_OK; +} + +bool +dfb_vt_switch( int num ) +{ + D_DEBUG_AT( VT, "%s( %d )\n", __FUNCTION__, num ); + + if (!dfb_config->vt_switching) + return false; + + D_DEBUG_AT( VT, " -> switching to vt %d...\n", num ); + + if (ioctl( dfb_vt->fd0, VT_ACTIVATE, num ) < 0) + D_PERROR( "DirectFB/fbdev/vt: VT_ACTIVATE failed\n" ); + + return true; +} + +static void * +vt_thread( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( VT, "%s( %p, %p )\n", __FUNCTION__, thread, arg ); + + pthread_mutex_lock( &dfb_vt->lock ); + + while (true) { + direct_thread_testcancel( thread ); + + D_DEBUG_AT( VT, "...%s (signal %d)\n", __FUNCTION__, dfb_vt->vt_sig); + + switch (dfb_vt->vt_sig) { + default: + D_BUG( "unexpected vt_sig" ); + /* fall through */ + + case -1: + pthread_cond_wait( &dfb_vt->wait, &dfb_vt->lock ); + continue; + + case SIG_SWITCH_FROM: + if (dfb_core_suspend( dfb_fbdev->core ) == DFB_OK) { + if (ioctl( dfb_vt->fd, VT_RELDISP, VT_ACKACQ ) < 0) + D_PERROR( "DirectFB/fbdev/vt: VT_RELDISP failed\n" ); + } + + break; + + case SIG_SWITCH_TO: + if (dfb_core_resume( dfb_fbdev->core ) == DFB_OK) { + if (ioctl( dfb_vt->fd, VT_RELDISP, VT_ACKACQ ) < 0) + D_PERROR( "DirectFB/fbdev/vt: VT_RELDISP failed\n" ); + + if (dfb_config->kd_graphics) { + if (ioctl( dfb_vt->fd, KDSETMODE, KD_GRAPHICS ) < 0) + D_PERROR( "DirectFB/fbdev/vt: KD_GRAPHICS failed!\n" ); + } + } + + break; + } + + dfb_vt->vt_sig = -1; + + pthread_cond_signal( &dfb_vt->wait ); + } + + return NULL; +} + +static void +vt_switch_handler( int signum ) +{ + D_DEBUG_AT( VT, "%s( %d )\n", __FUNCTION__, signum ); + + pthread_mutex_lock( &dfb_vt->lock ); + + while (dfb_vt->vt_sig != -1) + pthread_cond_wait( &dfb_vt->wait, &dfb_vt->lock ); + + dfb_vt->vt_sig = signum; + + pthread_cond_signal( &dfb_vt->wait ); + + pthread_mutex_unlock( &dfb_vt->lock ); +} + +static DFBResult +vt_init_switching( void ) +{ + struct termios ts; + const char cursoroff_str[] = "\033[?1;0;0c"; + const char blankoff_str[] = "\033[9;0]"; + char buf[32]; + + D_DEBUG_AT( VT, "%s()\n", __FUNCTION__ ); + + /* FIXME: Opening the device should be moved out of this function. */ + + snprintf(buf, 32, "/dev/tty%d", dfb_vt->num); + dfb_vt->fd = open( buf, O_RDWR | O_NOCTTY ); + if (dfb_vt->fd < 0) { + if (errno == ENOENT) { + snprintf(buf, 32, "/dev/vc/%d", dfb_vt->num); + dfb_vt->fd = open( buf, O_RDWR | O_NOCTTY ); + if (dfb_vt->fd < 0) { + if (errno == ENOENT) { + D_PERROR( "DirectFB/core/vt: Couldn't open " + "neither `/dev/tty%d' nor `/dev/vc/%d'!\n", + dfb_vt->num, dfb_vt->num ); + } + else { + D_PERROR( "DirectFB/core/vt: " + "Error opening `%s'!\n", buf ); + } + + return errno2result( errno ); + } + } + else { + D_PERROR( "DirectFB/core/vt: Error opening `%s'!\n", buf ); + return errno2result( errno ); + } + } + + /* attach to the new TTY before doing anything like KDSETMODE with it, + otherwise we'd get access denied error: */ + ioctl( dfb_vt->fd, TIOCSCTTY, 0 ); + + if (ioctl( dfb_vt->fd, KDSKBMODE, K_MEDIUMRAW ) < 0) { + D_PERROR( "DirectFB/fbdev/vt: K_MEDIUMRAW failed!\n" ); + close( dfb_vt->fd ); + return DFB_INIT; + } + + if (tcgetattr( dfb_vt->fd, &dfb_vt->old_ts ) < 0) { + D_PERROR( "DirectFB/fbdev/vt: tcgetattr failed!\n" ); + ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ); + close( dfb_vt->fd ); + return DFB_INIT; + } + ts = dfb_vt->old_ts; + ts.c_cc[VTIME] = 0; + ts.c_cc[VMIN] = 1; + ts.c_lflag &= ~(ICANON|ECHO|ISIG); + ts.c_iflag = 0; + if (tcsetattr( dfb_vt->fd, TCSAFLUSH, &ts ) < 0) { + D_PERROR( "DirectFB/fbdev/vt: tcsetattr for new values failed!\n" ); + ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ); + close( dfb_vt->fd ); + return DFB_INIT; + } + + write( dfb_vt->fd, cursoroff_str, sizeof(cursoroff_str) ); + if (dfb_config->kd_graphics) { + if (ioctl( dfb_vt->fd, KDSETMODE, KD_GRAPHICS ) < 0) { + D_PERROR( "DirectFB/fbdev/vt: KD_GRAPHICS failed!\n" ); + tcsetattr( dfb_vt->fd, TCSAFLUSH, &dfb_vt->old_ts ); + ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ); + close( dfb_vt->fd ); + return DFB_INIT; + } + } + else { + write( dfb_vt->fd, blankoff_str, sizeof(blankoff_str) ); + } + + if (dfb_config->vt_switching) { + struct vt_mode vt; + struct sigaction sig_tty; + + memset( &sig_tty, 0, sizeof( sig_tty ) ); + sig_tty.sa_handler = vt_switch_handler; + sigfillset( &sig_tty.sa_mask ); + + if (sigaction( SIG_SWITCH_FROM, &sig_tty, &dfb_vt->sig_usr1 ) || + sigaction( SIG_SWITCH_TO, &sig_tty, &dfb_vt->sig_usr2 )) { + D_PERROR( "DirectFB/fbdev/vt: sigaction failed!\n" ); + tcsetattr( dfb_vt->fd, TCSAFLUSH, &dfb_vt->old_ts ); + ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ); + close( dfb_vt->fd ); + return DFB_INIT; + } + + + vt.mode = VT_PROCESS; + vt.waitv = 0; + vt.relsig = SIG_SWITCH_FROM; + vt.acqsig = SIG_SWITCH_TO; + + if (ioctl( dfb_vt->fd, VT_SETMODE, &vt ) < 0) { + D_PERROR( "DirectFB/fbdev/vt: VT_SETMODE failed!\n" ); + + sigaction( SIG_SWITCH_FROM, &dfb_vt->sig_usr1, NULL ); + sigaction( SIG_SWITCH_TO, &dfb_vt->sig_usr2, NULL ); + + tcsetattr( dfb_vt->fd, TCSAFLUSH, &dfb_vt->old_ts ); + ioctl( dfb_vt->fd, KDSKBMODE, K_XLATE ); + close( dfb_vt->fd ); + + return DFB_INIT; + } + + direct_util_recursive_pthread_mutex_init( &dfb_vt->lock ); + + pthread_cond_init( &dfb_vt->wait, NULL ); + + dfb_vt->vt_sig = -1; + + dfb_vt->thread = direct_thread_create( DTT_CRITICAL, vt_thread, NULL, "VT Switcher" ); + } + + return DFB_OK; +} + +static int +vt_get_fb( int vt ) +{ + struct fb_con2fbmap c2m; + + D_DEBUG_AT( VT, "%s( %d )\n", __FUNCTION__, vt ); + + c2m.console = vt; + + if (ioctl( dfb_fbdev->fd, FBIOGET_CON2FBMAP, &c2m )) { + D_PERROR( "DirectFB/FBDev/vt: " + "FBIOGET_CON2FBMAP failed!\n" ); + return 0; + } + + D_DEBUG_AT( VT, " -> %d\n", c2m.framebuffer ); + + return c2m.framebuffer; +} + +static void +vt_set_fb( int vt, int fb ) +{ + struct fb_con2fbmap c2m; + struct stat sbf; + + D_DEBUG_AT( VT, "%s( %d, %d )\n", __FUNCTION__, vt, fb ); + + if (fstat( dfb_fbdev->fd, &sbf )) { + D_PERROR( "DirectFB/FBDev/vt: Could not fstat fb device!\n" ); + return; + } + + if (fb >= 0) + c2m.framebuffer = fb; + else + c2m.framebuffer = (sbf.st_rdev & 0xFF) >> 5; + + c2m.console = vt; + + if (ioctl( dfb_fbdev->fd, FBIOPUT_CON2FBMAP, &c2m ) < 0) { + D_PERROR( "DirectFB/FBDev/vt: " + "FBIOPUT_CON2FBMAP failed!\n" ); + } +} + +static void +vt_start_flushing( void ) +{ + dfb_vt->flush = true; + dfb_vt->flush_thread = direct_thread_create( DTT_DEFAULT, vt_flush_thread, NULL, "VT Flusher" ); +} + +static void +vt_stop_flushing( void ) +{ + dfb_vt->flush = false; + direct_thread_cancel( dfb_vt->flush_thread ); + direct_thread_join( dfb_vt->flush_thread ); + direct_thread_destroy( dfb_vt->flush_thread ); + dfb_vt->flush_thread = NULL; +} + +/* + * If the vt buffer in not kept clean the kernel may stop sleeping. + */ +static void * +vt_flush_thread( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( VT, "%s( %p, %p )\n", __FUNCTION__, thread, arg ); + + while (dfb_vt->flush) { + fd_set set; + int ret; + + FD_ZERO( &set ); + FD_SET( dfb_vt->fd, &set ); + + ret = select( dfb_vt->fd + 1, &set, NULL, NULL, NULL ); + + if (ret < 0 && errno == EINTR) + continue; + + if (ret < 0) + break; + + tcflush( dfb_vt->fd, TCIFLUSH ); + } + + return NULL; +} diff --git a/Source/DirectFB/systems/fbdev/vt.h b/Source/DirectFB/systems/fbdev/vt.h new file mode 100755 index 0000000..d9b1019 --- /dev/null +++ b/Source/DirectFB/systems/fbdev/vt.h @@ -0,0 +1,83 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __VT_H__ +#define __VT_H__ + +#include <signal.h> +#include <termios.h> +#include <unistd.h> +#include <linux/vt.h> + +#include <directfb.h> + +typedef struct { + int fd0; /* file descriptor of /dev/tty0 */ + int fd; /* file descriptor of /dev/ttyN + where N is the number of the allocated VT, + may be equal to 'fd0' if VT allocation + is disabled by "--no-vt-switch" */ + + int num; /* number of vt where DirectFB runs */ + int prev; /* number of vt DirectFB was started from */ + + int old_fb; /* original fb mapped to vt */ + + struct sigaction sig_usr1; /* previous signal handler for USR1 */ + struct sigaction sig_usr2; /* previous signal handler for USR2 */ + + struct vt_mode vt_mode; /* previous VT mode */ + + DirectThread *thread; + pthread_mutex_t lock; + pthread_cond_t wait; + + int vt_sig; + struct termios old_ts; + + bool flush; + DirectThread *flush_thread; +} VirtualTerminal; + +/* + * allocates and switches to a new virtual terminal + */ +DFBResult dfb_vt_initialize( void ); +DFBResult dfb_vt_join( void ); + +/* + * deallocates virtual terminal + */ +DFBResult dfb_vt_shutdown( bool emergency ); +DFBResult dfb_vt_leave( bool emergency ); + +DFBResult dfb_vt_detach( bool force ); + +bool dfb_vt_switch( int num ); + +#endif |