diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-09-30 14:18:15 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-09-30 14:18:15 +0000 |
commit | f25cb21322e90ab2c4d34d5bd8027006950662f6 (patch) | |
tree | f1986b6c009c7eba0d01e7a0297c5deec3163b97 /driver/xf86-video-nv | |
parent | da0ef05280ed34be0687c3802ab4724f7a9d063a (diff) |
xf86-video-nv 2.1.5
Diffstat (limited to 'driver/xf86-video-nv')
29 files changed, 9942 insertions, 126 deletions
diff --git a/driver/xf86-video-nv/README.G80 b/driver/xf86-video-nv/README.G80 index f168957c7..a49c3c85e 100644 --- a/driver/xf86-video-nv/README.G80 +++ b/driver/xf86-video-nv/README.G80 @@ -3,12 +3,7 @@ series of graphics processors. There are a few caveats of which to be aware: - The XVideo extension is not supported. - - With X servers prior to version 1.2.0 (X.org 7.2.0) on 64-bit Linux or most - non-Linux platforms, the driver may fail to restore the console due to bugs - in the server's x86 emulator. - The RENDER extension is not accelerated by this driver. - - Only one output can be used at a time. Work is in progress in the randr-1.2 - branch to support dual-head output. Bugs should be reported at http://bugs.freedesktop.org/ under the "xorg" product, "Driver/nVidia (open)" component. Please be sure to fill out the diff --git a/driver/xf86-video-nv/compat/Makefile.am b/driver/xf86-video-nv/compat/Makefile.am new file mode 100644 index 000000000..f5f8d936d --- /dev/null +++ b/driver/xf86-video-nv/compat/Makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = \ + parser/xf86Parser.h \ + parser/xf86Optrec.h \ + modes/xf86Crtc.c \ + modes/xf86Crtc.h \ + modes/xf86Cursors.c \ + modes/xf86cvt.c \ + modes/xf86DiDGA.c \ + modes/xf86EdidModes.c \ + modes/xf86Modes.c \ + modes/xf86Modes.h \ + modes/xf86RandR12.c \ + modes/xf86RandR12.h \ + modes/xf86Rename.h \ + modes/xf86Rotate.c diff --git a/driver/xf86-video-nv/compat/Makefile.in b/driver/xf86-video-nv/compat/Makefile.in new file mode 100644 index 000000000..7e991a4fa --- /dev/null +++ b/driver/xf86-video-nv/compat/Makefile.in @@ -0,0 +1,359 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 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@ +subdir = compat +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +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@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_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@ +modes_dir = @modes_dir@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +parser_dir = @parser_dir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + parser/xf86Parser.h \ + parser/xf86Optrec.h \ + modes/xf86Crtc.c \ + modes/xf86Crtc.h \ + modes/xf86Cursors.c \ + modes/xf86cvt.c \ + modes/xf86DiDGA.c \ + modes/xf86EdidModes.c \ + modes/xf86Modes.c \ + modes/xf86Modes.h \ + modes/xf86RandR12.c \ + modes/xf86RandR12.h \ + modes/xf86Rename.h \ + modes/xf86Rotate.c + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(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 compat/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu compat/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 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +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 +installdirs: +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 mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +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 -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool 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-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + +# 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/driver/xf86-video-nv/compat/README b/driver/xf86-video-nv/compat/README new file mode 100644 index 000000000..3e2b08954 --- /dev/null +++ b/driver/xf86-video-nv/compat/README @@ -0,0 +1,7 @@ +This directory contains a copy of the mode and parser code from RandR 1.2. + +If you are building from git and you don't have xorg-server-1.3 or higher or you +want to be able to make dist, you should create symlinks to the modes and parser +directories from a RandR 1.2-enabled server here: + + $ ln -s /path/to/xorg/xserver/hw/xfree86/{modes,parser} . diff --git a/driver/xf86-video-nv/compat/modes/xf86Crtc.c b/driver/xf86-video-nv/compat/modes/xf86Crtc.c new file mode 100644 index 000000000..d375da897 --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Crtc.c @@ -0,0 +1,2264 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" +#ifdef RENDER +#include "picturestr.h" +#endif + +#include "xf86xv.h" + +/* + * Initialize xf86CrtcConfig structure + */ + +int xf86CrtcConfigPrivateIndex = -1; + +_X_EXPORT void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs) +{ + xf86CrtcConfigPtr config; + + if (xf86CrtcConfigPrivateIndex == -1) + xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); + + config->funcs = funcs; + + scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; +} + +_X_EXPORT void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->minWidth = minWidth; + config->minHeight = minHeight; + config->maxWidth = maxWidth; + config->maxHeight = maxHeight; +} + +/* + * Crtc functions + */ +_X_EXPORT xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc, *crtcs; + + crtc = xcalloc (sizeof (xf86CrtcRec), 1); + if (!crtc) + return NULL; + crtc->scrn = scrn; + crtc->funcs = funcs; +#ifdef RANDR_12_INTERFACE + crtc->randr_crtc = NULL; +#endif + crtc->rotation = RR_Rotate_0; + crtc->desiredRotation = RR_Rotate_0; + if (xf86_config->crtc) + crtcs = xrealloc (xf86_config->crtc, + (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + else + crtcs = xalloc ((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + if (!crtcs) + { + xfree (crtc); + return NULL; + } + xf86_config->crtc = crtcs; + xf86_config->crtc[xf86_config->num_crtc++] = crtc; + return crtc; +} + +_X_EXPORT void +xf86CrtcDestroy (xf86CrtcPtr crtc) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + int c; + + (*crtc->funcs->destroy) (crtc); + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c] == crtc) + { + memmove (&xf86_config->crtc[c], + &xf86_config->crtc[c+1], + ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); + xf86_config->num_crtc--; + break; + } + xfree (crtc); +} + + +/** + * Return whether any outputs are connected to the specified pipe + */ + +_X_EXPORT Bool +xf86CrtcInUse (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o]->crtc == crtc) + return TRUE; + return FALSE; +} + +_X_EXPORT void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) +{ +#ifdef RENDER + int subpixel_order = SubPixelUnknown; + Bool has_none = FALSE; + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + + if (output->crtc == crtc) + { + switch (output->subpixel_order) { + case SubPixelNone: + has_none = TRUE; + break; + case SubPixelUnknown: + break; + default: + subpixel_order = output->subpixel_order; + break; + } + } + if (subpixel_order != SubPixelUnknown) + break; + } + if (subpixel_order != SubPixelUnknown) + { + static const int circle[4] = { + SubPixelHorizontalRGB, + SubPixelVerticalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalBGR, + }; + int rotate; + int c; + for (rotate = 0; rotate < 4; rotate++) + if (crtc->rotation & (1 << rotate)) + break; + for (c = 0; c < 4; c++) + if (circle[c] == subpixel_order) + break; + c = (c + rotate) & 0x3; + if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) + c ^= 2; + if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) + c ^= 2; + subpixel_order = circle[c]; + break; + } + } + if (subpixel_order == SubPixelUnknown && has_none) + subpixel_order = SubPixelNone; + PictureSetSubpixelOrder (pScreen, subpixel_order); +#endif +} + +/** + * Sets the given video mode on the given crtc + */ +_X_EXPORT Bool +xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + Bool ret = FALSE; + Bool didLock = FALSE; + DisplayModePtr adjusted_mode; + DisplayModeRec saved_mode; + int saved_x, saved_y; + Rotation saved_rotation; + + crtc->enabled = xf86CrtcInUse (crtc); + + if (!crtc->enabled) + { + /* XXX disable crtc? */ + return TRUE; + } + + adjusted_mode = xf86DuplicateMode(mode); + + didLock = crtc->funcs->lock (crtc); + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + + /* XXX short-circuit changes to base location only */ + + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + goto done; + } + } + + if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + goto done; + } + + if (!xf86CrtcRotate (crtc, mode, rotation)) { + goto done; + } + + /* Prepare the outputs and CRTCs before setting the mode. */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->prepare(output); + } + + crtc->funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->mode_set(output, mode, adjusted_mode); + } + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc->funcs->commit(crtc); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + { + output->funcs->commit(output); +#ifdef RANDR_12_INTERFACE + if (output->randr_output) + RRPostPendingProperties (output->randr_output); +#endif + } + } + + /* XXX free adjustedmode */ + ret = TRUE; + if (scrn->pScreen) + xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); + +done: + if (!ret) { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + } + + if (didLock) + crtc->funcs->unlock (crtc); + + return ret; +} + +/* + * Output functions + */ + +extern XF86ConfigPtr xf86configptr; + +typedef enum { + OPTION_PREFERRED_MODE, + OPTION_POSITION, + OPTION_BELOW, + OPTION_RIGHT_OF, + OPTION_ABOVE, + OPTION_LEFT_OF, + OPTION_ENABLE, + OPTION_DISABLE, + OPTION_MIN_CLOCK, + OPTION_MAX_CLOCK, + OPTION_IGNORE, + OPTION_ROTATE, +} OutputOpts; + +static OptionInfoRec xf86OutputOptions[] = { + {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, + {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, + {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, + {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, + {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +enum { + OPTION_MODEDEBUG, +}; + +static OptionInfoRec xf86DeviceOptions[] = { + {OPTION_MODEDEBUG, "ModeDebug", OPTV_STRING, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static void +xf86OutputSetMonitor (xf86OutputPtr output) +{ + char *option_name; + static const char monitor_prefix[] = "monitor-"; + char *monitor; + + if (!output->name) + return; + + if (output->options) + xfree (output->options); + + output->options = xnfalloc (sizeof (xf86OutputOptions)); + memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); + + option_name = xnfalloc (strlen (monitor_prefix) + + strlen (output->name) + 1); + strcpy (option_name, monitor_prefix); + strcat (option_name, output->name); + monitor = xf86findOptionValue (output->scrn->options, option_name); + if (!monitor) + monitor = output->name; + else + xf86MarkOptionUsedByName (output->scrn->options, option_name); + xfree (option_name); + output->conf_monitor = xf86findMonitor (monitor, + xf86configptr->conf_monitor_lst); + /* + * Find the monitor section of the screen and use that + */ + if (!output->conf_monitor && output->use_screen_monitor) + output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, + xf86configptr->conf_monitor_lst); + if (output->conf_monitor) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s using monitor section %s\n", + output->name, output->conf_monitor->mon_identifier); + xf86ProcessOptions (output->scrn->scrnIndex, + output->conf_monitor->mon_option_lst, + output->options); + } + else + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s has no monitor section\n", + output->name); +} + +static Bool +xf86OutputEnabled (xf86OutputPtr output) +{ + Bool enable, disable; + + /* check to see if this output was enabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s enabled by config file\n", output->name); + return TRUE; + } + /* or if this output was disabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s disabled by config file\n", output->name); + return FALSE; + } + /* otherwise, enable if it is not disconnected */ + enable = output->status != XF86OutputStatusDisconnected; + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s %sconnected\n", output->name, enable ? "" : "dis"); + return enable; +} + +static Bool +xf86OutputIgnored (xf86OutputPtr output) +{ + return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); +} + +static char *direction[4] = { + "normal", + "left", + "inverted", + "right" +}; + +static Rotation +xf86OutputInitialRotation (xf86OutputPtr output) +{ + char *rotate_name = xf86GetOptValString (output->options, + OPTION_ROTATE); + int i; + + if (!rotate_name) + return RR_Rotate_0; + + for (i = 0; i < 4; i++) + if (xf86nameCompare (direction[i], rotate_name) == 0) + return (1 << i); + return RR_Rotate_0; +} + +_X_EXPORT xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name) +{ + xf86OutputPtr output, *outputs; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int len; + + if (name) + len = strlen (name) + 1; + else + len = 0; + + output = xcalloc (sizeof (xf86OutputRec) + len, 1); + if (!output) + return NULL; + output->scrn = scrn; + output->funcs = funcs; + if (name) + { + output->name = (char *) (output + 1); + strcpy (output->name, name); + } + output->subpixel_order = SubPixelUnknown; + /* + * Use the old per-screen monitor section for the first output + */ + output->use_screen_monitor = (xf86_config->num_output == 0); +#ifdef RANDR_12_INTERFACE + output->randr_output = NULL; +#endif + if (name) + { + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + { + xfree (output); + return FALSE; + } + } + + + if (xf86_config->output) + outputs = xrealloc (xf86_config->output, + (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + else + outputs = xalloc ((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + if (!outputs) + { + xfree (output); + return NULL; + } + + xf86_config->output = outputs; + xf86_config->output[xf86_config->num_output++] = output; + + return output; +} + +_X_EXPORT Bool +xf86OutputRename (xf86OutputPtr output, const char *name) +{ + int len = strlen(name) + 1; + char *newname = xalloc (len); + + if (!newname) + return FALSE; /* so sorry... */ + + strcpy (newname, name); + if (output->name && output->name != (char *) (output + 1)) + xfree (output->name); + output->name = newname; + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + return FALSE; + return TRUE; +} + +_X_EXPORT void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) +{ + if (use_screen_monitor != output->use_screen_monitor) + { + output->use_screen_monitor = use_screen_monitor; + xf86OutputSetMonitor (output); + } +} + +_X_EXPORT void +xf86OutputDestroy (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + (*output->funcs->destroy) (output); + while (output->probed_modes) + xf86DeleteMode (&output->probed_modes, output->probed_modes); + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o] == output) + { + memmove (&xf86_config->output[o], + &xf86_config->output[o+1], + ((xf86_config->num_output - (o + 1)) * sizeof(void*))); + xf86_config->num_output--; + break; + } + if (output->name && output->name != (char *) (output + 1)) + xfree (output->name); + xfree (output); +} + +/* + * Called during CreateScreenResources to hook up RandR + */ +static Bool +xf86CrtcCreateScreenResources (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + screen->CreateScreenResources = config->CreateScreenResources; + + if (!(*screen->CreateScreenResources)(screen)) + return FALSE; + + if (!xf86RandR12CreateScreenResources (screen)) + return FALSE; + + return TRUE; +} + +/* + * Clean up config on server reset + */ +static Bool +xf86CrtcCloseScreen (int index, ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + + screen->CloseScreen = config->CloseScreen; + + xf86RotateCloseScreen (screen); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = NULL; + } + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = NULL; + } + return screen->CloseScreen (index, screen); +} + +/* + * Called at ScreenInit time to set up + */ +_X_EXPORT Bool +xf86CrtcScreenInit (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* Rotation */ + xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); + xf86DisableRandR(); /* Disable old RandR extension support */ + xf86RandR12Init (screen); + + /* support all rotations if every crtc has the shadow alloc funcs */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) + break; + } + if (c == config->num_crtc) + xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | + RR_Rotate_180 | RR_Rotate_270 | + RR_Reflect_X | RR_Reflect_Y); + else + xf86RandR12SetRotations (screen, RR_Rotate_0); + + /* Wrap CreateScreenResources so we can initialize the RandR code */ + config->CreateScreenResources = screen->CreateScreenResources; + screen->CreateScreenResources = xf86CrtcCreateScreenResources; + + config->CloseScreen = screen->CloseScreen; + screen->CloseScreen = xf86CrtcCloseScreen; + + return TRUE; +} + +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = 203; /* 768 pixels at 96dpi */ + /* + * Pick a mode closest to 96dpi + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + int preferred = (mode->type & M_T_PREFERRED) != 0; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* yes, use VDisplay here, not xf86ModeHeight */ + dpi = (mode->VDisplay * 254) / (mm_height * 10); + diff = dpi - 96; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, + DisplayModePtr match, Rotation match_rotation, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* exact matches are preferred */ + if (output->initial_rotation == match_rotation && + xf86ModesEqual (mode, match)) + return mode; + + dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); + dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static Bool +xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + if (mode->type & M_T_PREFERRED) + return TRUE; + } + return FALSE; +} + +static int +xf86PickCrtcs (ScrnInfoPtr scrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n, + int width, + int height) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output, width, height)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n]) && + config->output[0]->initial_rotation == config->output[n]->initial_rotation && + config->output[o]->initial_x == config->output[n]->initial_x && + config->output[o]->initial_y == config->output[n]->initial_y) + { + if ((output->possible_clones & (1 << o)) == 0) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); + if (score > best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + xfree (crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in the specified configuration. + * + * canGrow indicates that the driver can make the screen larger than its initial + * configuration. If FALSE, this function will enlarge the screen to include + * the largest available mode. + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, + Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 0, crtc_height = 0; + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc->enabled) + { + crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); + crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); + } + if (!canGrow) { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_width = mode->VDisplay; + if (mode->VDisplay > crtc_height) + crtc_height = mode->VDisplay; + if (mode->HDisplay > crtc_height) + crtc_height = mode->HDisplay; + } + } + } + } + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + } + if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; + if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; + if (config->minWidth && width < config->minWidth) width = config->minWidth; + if (config->minHeight && height < config->minHeight) height = config->minHeight; + *widthp = width; + *heightp = height; +} + +#define POSITION_UNSET -100000 + +static Bool +xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + int min_x, min_y; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x = output->initial_y = POSITION_UNSET; + } + + /* + * Loop until all outputs are set + */ + for (;;) + { + Bool any_set = FALSE; + Bool keep_going = FALSE; + + for (o = 0; o < config->num_output; o++) + { + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + xf86OutputPtr output = config->output[o]; + xf86OutputPtr relative; + char *relative_name; + char *position; + OutputOpts relation; + int r; + + if (output->initial_x != POSITION_UNSET) + continue; + position = xf86GetOptValString (output->options, + OPTION_POSITION); + /* + * Absolute position wins + */ + if (position) + { + int x, y; + if (sscanf (position, "%d %d", &x, &y) == 2) + { + output->initial_x = x; + output->initial_y = y; + } + else + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s position not of form \"x y\"\n", + output->name); + output->initial_x = output->initial_y = 0; + } + any_set = TRUE; + continue; + } + /* + * Next comes relative positions + */ + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + { + int or; + relative = NULL; + for (or = 0; or < config->num_output; or++) + { + xf86OutputPtr out_rel = config->output[or]; + XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; + + if (rel_mon) + { + if (xf86nameCompare (rel_mon->mon_identifier, + relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (strcmp (out_rel->name, relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (!relative) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to unknown output %s\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (relative->initial_x == POSITION_UNSET) + { + keep_going = TRUE; + continue; + } + output->initial_x = relative->initial_x; + output->initial_y = relative->initial_y; + switch (relation) { + case OPTION_BELOW: + output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_RIGHT_OF: + output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); + break; + case OPTION_ABOVE: + output->initial_y -= xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_LEFT_OF: + output->initial_x -= xf86ModeWidth (modes[or], relative->initial_rotation); + break; + default: + break; + } + any_set = TRUE; + continue; + } + + /* Nothing set, just stick them at 0,0 */ + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + } + if (!keep_going) + break; + if (!any_set) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->initial_x == POSITION_UNSET) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output position loop. Moving %s to 0,0\n", + output->name); + output->initial_x = output->initial_y = 0; + break; + } + } + } + } + + /* + * normalize positions + */ + min_x = 1000000; + min_y = 1000000; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->initial_x < min_x) + min_x = output->initial_x; + if (output->initial_y < min_y) + min_y = output->initial_y; + } + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x -= min_x; + output->initial_y -= min_y; + } + return TRUE; +} + +/* + * XXX walk the monitor mode list and prune out duplicates that + * are inserted by xf86DDCMonitorSet. In an ideal world, that + * function would do this work by itself. + */ + +static void +xf86PruneDuplicateMonitorModes (MonPtr Monitor) +{ + DisplayModePtr master, clone, next; + + for (master = Monitor->Modes; + master && master != Monitor->Last; + master = master->next) + { + for (clone = master->next; clone && clone != Monitor->Modes; clone = next) + { + next = clone->next; + if (xf86ModesEqual (master, clone)) + { + if (Monitor->Last == clone) + Monitor->Last = clone->prev; + xf86DeleteMode (&Monitor->Modes, clone); + } + } + } +} + +/** Return - 0 + if a should be earlier, same or later than b in list + */ +static int +xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) +{ + int diff; + + diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); + if (diff) + return diff; + diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; + if (diff) + return diff; + diff = b->Clock - a->Clock; + return diff; +} + +/** + * Insertion sort input in-place and return the resulting head + */ +static DisplayModePtr +xf86SortModes (DisplayModePtr input) +{ + DisplayModePtr output = NULL, i, o, n, *op, prev; + + /* sort by preferred status and pixel area */ + while (input) + { + i = input; + input = input->next; + for (op = &output; (o = *op); op = &o->next) + if (xf86ModeCompare (o, i) > 0) + break; + i->next = *op; + *op = i; + } + /* prune identical modes */ + for (o = output; o && (n = o->next); o = n) + { + if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) + { + o->next = n->next; + xfree (n->name); + xfree (n); + n = o; + } + } + /* hook up backward links */ + prev = NULL; + for (o = output; o; o = o->next) + { + o->prev = prev; + prev = o; + } + return output; +} + +_X_EXPORT void +xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + /* When canGrow was TRUE in the initial configuration we have to + * compare against the maximum values so that we don't drop modes. + * When canGrow was FALSE, the maximum values would have been clamped + * anyway. + */ + if (maxX == 0 || maxY == 0) { + maxX = config->maxWidth; + maxY = config->maxHeight; + } + + /* Elide duplicate modes before defaulting code uses them */ + xf86PruneDuplicateMonitorModes (scrn->monitor); + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + DisplayModePtr config_modes = NULL, output_modes, default_modes; + char *preferred_mode; + xf86MonPtr edid_monitor; + XF86ConfMonitorPtr conf_monitor; + MonRec mon_rec; + int min_clock = 0; + int max_clock = 0; + double clock; + enum { sync_config, sync_edid, sync_default } sync_source = sync_default; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + /* + * Check connection status + */ + output->status = (*output->funcs->detect)(output); + + if (output->status == XF86OutputStatusDisconnected) + { + xf86OutputSetEDID (output, NULL); + continue; + } + + memset (&mon_rec, '\0', sizeof (mon_rec)); + + conf_monitor = output->conf_monitor; + + if (conf_monitor) + { + int i; + + for (i = 0; i < conf_monitor->mon_n_hsync; i++) + { + mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; + mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; + mon_rec.nHsync++; + sync_source = sync_config; + } + for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; + mon_rec.nVrefresh++; + sync_source = sync_config; + } + config_modes = xf86GetMonitorModes (scrn, conf_monitor); + } + + output_modes = (*output->funcs->get_modes) (output); + + edid_monitor = output->MonInfo; + + if (edid_monitor) + { + int i; + Bool set_hsync = mon_rec.nHsync == 0; + Bool set_vrefresh = mon_rec.nVrefresh == 0; + + for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++) + { + if (edid_monitor->det_mon[i].type == DS_RANGES) + { + struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges; + if (set_hsync && ranges->max_h) + { + mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h; + mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h; + mon_rec.nHsync++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (set_vrefresh && ranges->max_v) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v; + mon_rec.nVrefresh++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (ranges->max_clock > max_clock) + max_clock = ranges->max_clock; + } + } + } + + if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, + OPTUNITS_KHZ, &clock)) + min_clock = (int) clock; + if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, + OPTUNITS_KHZ, &clock)) + max_clock = (int) clock; + + /* + * These limits will end up setting a 1024x768@60Hz mode by default, + * which seems like a fairly good mode to use when nothing else is + * specified + */ + if (mon_rec.nHsync == 0) + { + mon_rec.hsync[0].lo = 31.0; + mon_rec.hsync[0].hi = 55.0; + mon_rec.nHsync = 1; + } + if (mon_rec.nVrefresh == 0) + { + mon_rec.vrefresh[0].lo = 58.0; + mon_rec.vrefresh[0].hi = 62.0; + mon_rec.nVrefresh = 1; + } + default_modes = xf86GetDefaultModes (output->interlaceAllowed, + output->doubleScanAllowed); + + if (sync_source == sync_config) + { + /* + * Check output and config modes against sync range from config file + */ + xf86ValidateModesSync (scrn, output_modes, &mon_rec); + xf86ValidateModesSync (scrn, config_modes, &mon_rec); + } + /* + * Check default modes against sync range + */ + xf86ValidateModesSync (scrn, default_modes, &mon_rec); + /* + * Check default modes against monitor max clock + */ + if (max_clock) + xf86ValidateModesClocks(scrn, default_modes, + &min_clock, &max_clock, 1); + + output->probed_modes = NULL; + output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); + + /* + * Check all modes against max size + */ + if (maxX && maxY) + xf86ValidateModesSize (scrn, output->probed_modes, + maxX, maxY, 0); + + /* + * Check all modes against output + */ + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output, mode); + + xf86PruneInvalidModes(scrn, &output->probed_modes, + config->debug_modes); + + output->probed_modes = xf86SortModes (output->probed_modes); + + /* Check for a configured preference for a particular mode */ + preferred_mode = xf86GetOptValString (output->options, + OPTION_PREFERRED_MODE); + + if (preferred_mode) + { + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (!strcmp (preferred_mode, mode->name)) + { + if (mode != output->probed_modes) + { + if (mode->prev) + mode->prev->next = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + mode->next = output->probed_modes; + output->probed_modes->prev = mode; + mode->prev = NULL; + output->probed_modes = mode; + } + mode->type |= M_T_PREFERRED; + } + else + mode->type &= ~M_T_PREFERRED; + } + } + + output->initial_rotation = xf86OutputInitialRotation (output); + + if (config->debug_modes) { + if (output->probed_modes != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } + } + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + if (config->debug_modes) + xf86PrintModeline(scrn->scrnIndex, mode); + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +_X_EXPORT void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); + +_X_EXPORT void +xf86SetScrnInfoModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode; + + output = config->output[config->compat_output]; + if (!output->crtc) + { + int o; + + output = NULL; + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc) + { + config->compat_output = o; + output = config->output[o]; + break; + } + /* no outputs are active, punt and leave things as they are */ + if (!output) + return; + } + crtc = output->crtc; + + /* Clear any existing modes from scrn->modes */ + while (scrn->modes != NULL) + xf86DeleteMode(&scrn->modes, scrn->modes); + + /* Set scrn->modes to the mode list for the 'compat' output */ + scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); + + for (mode = scrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + + if (scrn->modes != NULL) { + /* For some reason, scrn->modes is circular, unlike the other mode + * lists. How great is that? + */ + for (last = scrn->modes; last && last->next; last = last->next) + ; + last->next = scrn->modes; + scrn->modes->prev = last; + if (mode) { + while (scrn->modes != mode) + scrn->modes = scrn->modes->next; + } + } + scrn->currentMode = scrn->modes; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + * + * canGrow indicates that the driver can resize the screen to larger than its + * initially configured size via the config->funcs->resize hook. If TRUE, this + * function will set virtualX and virtualY to match the initial configuration + * and leave config->max{Width,Height} alone. If FALSE, it will bloat + * virtual[XY] to include the largest modes and set config->max{Width,Height} + * accordingly. + */ + +_X_EXPORT Bool +xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + DisplayModePtr target_mode = NULL; + Rotation target_rotation = RR_Rotate_0; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + Bool *enabled; + int width; + int height; + + /* Set up the device options */ + config->options = xnfalloc (sizeof (xf86DeviceOptions)); + memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); + xf86ProcessOptions (scrn->scrnIndex, + scrn->options, + config->options); + config->debug_modes = xf86ReturnOptValBool (config->options, + OPTION_MODEDEBUG, FALSE); + + if (scrn->display->virtualX) + width = scrn->display->virtualX; + else + width = config->maxWidth; + if (scrn->display->virtualY) + height = scrn->display->virtualY; + else + height = config->maxHeight; + + xf86ProbeOutputModes (scrn, width, height); + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + enabled = xnfcalloc (config->num_output, sizeof (Bool)); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + modes[o] = NULL; + enabled[o] = xf86OutputEnabled (output); + } + + /* + * Let outputs with preferred modes drive screen size + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (enabled[o] && + xf86OutputHasPreferredMode (output, width, height)) + { + target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + if (!target_mode) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (enabled[o]) + { + target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + } + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (enabled[o]) + { + if (!modes[o]) + modes[o] = xf86ClosestMode (output, target_mode, + target_rotation, width, height); + if (!modes[o]) + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s enabled but has no modes\n", + output->name); + else + xf86DrvMsg (scrn->scrnIndex, X_INFO, + "Output %s using initial mode %s\n", + output->name, modes[o]->name); + } + } + + /* + * Set the position of each output + */ + if (!xf86InitialOutputPositions (scrn, modes)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* + * Assign CRTCs to fit output configuration + */ + if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* XXX override xf86 common frame computation code */ + + scrn->display->frameX0 = 0; + scrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + } + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->desiredRotation = output->initial_rotation; + crtc->desiredX = output->initial_x; + crtc->desiredY = output->initial_y; + crtc->enabled = TRUE; + crtc->x = output->initial_x; + crtc->y = output->initial_y; + output->crtc = crtc; + } + } + + if (scrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover the current config and potential mode + * switches, if the driver can't enlarge the screen later. + */ + xf86DefaultScreenLimits (scrn, &width, &height, canGrow); + + scrn->display->virtualX = width; + scrn->display->virtualY = height; + } + + if (width > scrn->virtualX) + scrn->virtualX = width; + if (height > scrn->virtualY) + scrn->virtualY = height; + + /* + * Make sure the configuration isn't too small. + */ + if (width < config->minWidth || height < config->minHeight) + return FALSE; + + /* + * Limit the crtc config to virtual[XY] if the driver can't grow the + * desktop. + */ + if (!canGrow) + { + xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, + width, height); + } + + /* Mirror output modes to scrn mode list */ + xf86SetScrnInfoModes (scrn); + + xfree (crtcs); + xfree (modes); + return TRUE; +} + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +_X_EXPORT Bool +xf86SetDesiredModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + /* + * Turn off everything so mode setting is done + * with hardware in a consistent state + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + xf86OutputPtr output = NULL; + int o; + + if (config->output[config->compat_output]->crtc == crtc) + output = config->output[config->compat_output]; + else + { + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc == crtc) + { + output = config->output[o]; + break; + } + } + /* + * Skip disabled crtcs + */ + if (!output) + continue; + + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) + { + DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); + + if (!mode) + return FALSE; + crtc->desiredMode = *mode; + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (!xf86CrtcSetMode (crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) + return FALSE; + } + + xf86DisableUnusedFunctions(scrn); + return TRUE; +} + +/** + * In the current world order, there are lists of modes per output, which may + * or may not include the mode that was asked to be set by XFree86's mode + * selection. Find the closest one, in the following preference order: + * + * - Equality + * - Closer in size to the requested mode, but no larger + * - Closer in refresh rate to the requested mode. + */ + +_X_EXPORT DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) +{ + DisplayModePtr best = NULL, scan = NULL; + + for (scan = output->probed_modes; scan != NULL; scan = scan->next) + { + /* If there's an exact match, we're done. */ + if (xf86ModesEqual(scan, desired)) { + best = desired; + break; + } + + /* Reject if it's larger than the desired mode. */ + if (scan->HDisplay > desired->HDisplay || + scan->VDisplay > desired->VDisplay) + { + continue; + } + + /* + * If we haven't picked a best mode yet, use the first + * one in the size range + */ + if (best == NULL) + { + best = scan; + continue; + } + + /* Find if it's closer to the right size than the current best + * option. + */ + if ((scan->HDisplay > best->HDisplay && + scan->VDisplay >= best->VDisplay) || + (scan->HDisplay >= best->HDisplay && + scan->VDisplay > best->VDisplay)) + { + best = scan; + continue; + } + + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (scan->HDisplay == best->HDisplay && + scan->VDisplay == best->VDisplay && + (fabs(scan->VRefresh - desired->VRefresh) < + fabs(best->VRefresh - desired->VRefresh))) { + best = scan; + } + } + return best; +} + +/** + * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, + * take the specified mode and apply it to the crtc connected to the compat + * output. Then, find similar modes for the other outputs, as with the + * InitialConfiguration code above. The goal is to clone the desired + * mode across all outputs that are currently active. + */ + +_X_EXPORT Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool ok = TRUE; + xf86OutputPtr compat_output = config->output[config->compat_output]; + DisplayModePtr compat_mode; + int c; + + /* + * Let the compat output drive the final mode selection + */ + compat_mode = xf86OutputFindClosestMode (compat_output, desired); + if (compat_mode) + desired = compat_mode; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + DisplayModePtr crtc_mode = NULL; + int o; + + if (!crtc->enabled) + continue; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr output_mode; + + /* skip outputs not on this crtc */ + if (output->crtc != crtc) + continue; + + if (crtc_mode) + { + output_mode = xf86OutputFindClosestMode (output, crtc_mode); + if (output_mode != crtc_mode) + output->crtc = NULL; + } + else + crtc_mode = xf86OutputFindClosestMode (output, desired); + } + if (!crtc_mode) + { + crtc->enabled = FALSE; + continue; + } + if (!xf86CrtcSetMode (crtc, crtc_mode, rotation, 0, 0)) + ok = FALSE; + else + { + crtc->desiredMode = *crtc_mode; + crtc->desiredRotation = rotation; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + } + xf86DisableUnusedFunctions(pScrn); +#if RANDR_12_INTERFACE + xf86RandR12TellChanged (pScrn->pScreen); +#endif + return ok; +} + + +/** + * Set the DPMS power mode of all outputs and CRTCs. + * + * If the new mode is off, it will turn off outputs and then CRTCs. + * Otherwise, it will affect CRTCs before outputs. + */ +_X_EXPORT void +xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + + if (!scrn->vtSema) + return; + + if (mode == DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + if (crtc->enabled) + (*crtc->funcs->dpms) (crtc, mode); + } + + if (mode != DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } +} + +/** + * Implement the screensaver by just calling down into the driver DPMS hooks. + * + * Even for monitors with no DPMS support, by the definition of our DPMS hooks, + * the outputs will still get disabled (blanked). + */ +_X_EXPORT Bool +xf86SaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (xf86IsUnblank(mode)) + xf86DPMSSet(pScrn, DPMSModeOn, 0); + else + xf86DPMSSet(pScrn, DPMSModeOff, 0); + + return TRUE; +} + +/** + * Disable all inactive crtcs and outputs + */ +_X_EXPORT void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + if (!output->crtc) + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + { + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + } + } +} + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID_DATA" + +/** + * Set the RandR EDID property + */ +static void +xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE, TRUE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} + +#endif + +/** + * Set the EDID information for the specified output + */ +_X_EXPORT void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; +#ifdef RANDR_12_INTERFACE + int size; +#endif + + if (output->MonInfo != NULL) + xfree(output->MonInfo); + + output->MonInfo = edid_mon; + + if (config->debug_modes) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", + output->name); + xf86PrintEDID(edid_mon); + } + + /* Set the DDC properties for the 'compat' output */ + if (output == config->output[config->compat_output]) + xf86SetDDCproperties(scrn, edid_mon); + +#ifdef RANDR_12_INTERFACE + /* Set the RandR output properties */ + size = 0; + if (edid_mon) + { + if (edid_mon->ver.version == 1) + size = 128; + else if (edid_mon->ver.version == 2) + size = 256; + } + xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); +#endif + + if (edid_mon) + { + /* Pull out a phyiscal size from a detailed timing if available. */ + for (i = 0; i < 4; i++) { + if (edid_mon->det_mon[i].type == DT && + edid_mon->det_mon[i].section.d_timings.h_size != 0 && + edid_mon->det_mon[i].section.d_timings.v_size != 0) + { + output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size; + output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size; + break; + } + } + + /* if no mm size is available from a detailed timing, check the max size field */ + if ((!output->mm_width || !output->mm_height) && + (edid_mon->features.hsize && edid_mon->features.vsize)) + { + output->mm_width = edid_mon->features.hsize * 10; + output->mm_height = edid_mon->features.vsize * 10; + } + } +} + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +_X_EXPORT DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr edid_mon = output->MonInfo; + + if (!edid_mon) + return NULL; + return xf86DDCGetModes(scrn->scrnIndex, edid_mon); +} + +_X_EXPORT xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) +{ + ScrnInfoPtr scrn = output->scrn; + + return xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus); +} + +static char *_xf86ConnectorNames[] = { "None", "VGA", "DVI-I", "DVI-D", + "DVI-A", "Composite", "S-Video", + "Component", "LFP", "Proprietary" }; +_X_EXPORT char * +xf86ConnectorGetName(xf86ConnectorType connector) +{ + return _xf86ConnectorNames[connector]; +} + +static void +x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) +{ + dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; + dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; + dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; + dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; + + if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) + dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; +} + +static void +x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) +{ + if (crtc->enabled) { + crtc_box->x1 = crtc->x; + crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); + crtc_box->y1 = crtc->y; + crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); + } else + crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; +} + +static int +xf86_crtc_box_area(BoxPtr box) +{ + return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ + +static xf86CrtcPtr +xf86_covering_crtc(ScrnInfoPtr pScrn, + BoxPtr box, + xf86CrtcPtr desired, + BoxPtr crtc_box_ret) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc, best_crtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + best_crtc = NULL; + best_coverage = 0; + crtc_box_ret->x1 = 0; + crtc_box_ret->x2 = 0; + crtc_box_ret->y1 = 0; + crtc_box_ret->y2 = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + x86_crtc_box(crtc, &crtc_box); + x86_crtc_box_intersect(&cover_box, &crtc_box, box); + coverage = xf86_crtc_box_area(&cover_box); + if (coverage && crtc == desired) { + *crtc_box_ret = crtc_box; + return crtc; + } else if (coverage > best_coverage) { + *crtc_box_ret = crtc_box; + best_crtc = crtc; + best_coverage = coverage; + } + } + return best_crtc; +} + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that + */ + +_X_EXPORT Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height) +{ + Bool ret; + RegionRec crtc_region_local; + RegionPtr crtc_region = reg; + + if (crtc_ret) { + BoxRec crtc_box; + xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, + desired_crtc, + &crtc_box); + + if (crtc) { + REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); + crtc_region = &crtc_region_local; + REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); + } + *crtc_ret = crtc; + } + + ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, + crtc_region, width, height); + + if (crtc_region != reg) + REGION_UNINIT (pScreen, &crtc_region_local); + + return ret; +} diff --git a/driver/xf86-video-nv/compat/modes/xf86Crtc.h b/driver/xf86-video-nv/compat/modes/xf86Crtc.h new file mode 100644 index 000000000..9693e12bb --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Crtc.h @@ -0,0 +1,788 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#ifndef _XF86CRTC_H_ +#define _XF86CRTC_H_ + +#include <edid.h> +#include "randrstr.h" +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif +#include "xf86Modes.h" +#include "xf86Cursor.h" +#include "damage.h" +#include "picturestr.h" + +/* Compat definitions for older X Servers. */ +#ifndef M_T_PREFERRED +#define M_T_PREFERRED 0x08 +#endif +#ifndef M_T_DRIVER +#define M_T_DRIVER 0x40 +#endif +#ifndef HARDWARE_CURSOR_ARGB +#define HARDWARE_CURSOR_ARGB 0x00004000 +#endif + +typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr; +typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr; + +/* define a standard for connector types */ +typedef enum _xf86ConnectorType { + XF86ConnectorNone, + XF86ConnectorVGA, + XF86ConnectorDVI_I, + XF86ConnectorDVI_D, + XF86ConnectorDVI_A, + XF86ConnectorComposite, + XF86ConnectorSvideo, + XF86ConnectorComponent, + XF86ConnectorLFP, + XF86ConnectorProprietary, +} xf86ConnectorType; + +typedef enum _xf86OutputStatus { + XF86OutputStatusConnected, + XF86OutputStatusDisconnected, + XF86OutputStatusUnknown, +} xf86OutputStatus; + +typedef struct _xf86CrtcFuncs { + /** + * Turns the crtc on/off, or sets intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. If the + * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to + * be safe to call mode_set. + */ + void + (*dpms)(xf86CrtcPtr crtc, + int mode); + + /** + * Saves the crtc's state for restoration on VT switch. + */ + void + (*save)(xf86CrtcPtr crtc); + + /** + * Restore's the crtc's state at VT switch. + */ + void + (*restore)(xf86CrtcPtr crtc); + + /** + * Lock CRTC prior to mode setting, mostly for DRI. + * Returns whether unlock is needed + */ + Bool + (*lock) (xf86CrtcPtr crtc); + + /** + * Unlock CRTC after mode setting, mostly for DRI + */ + void + (*unlock) (xf86CrtcPtr crtc); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows a CRTC to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool + (*mode_fixup)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Prepare CRTC for an upcoming mode set. + */ + void + (*prepare)(xf86CrtcPtr crtc); + + /** + * Callback for setting up a video mode after fixups have been made. + */ + void + (*mode_set)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode, + int x, int y); + + /** + * Commit mode changes to a CRTC + */ + void + (*commit)(xf86CrtcPtr crtc); + + /* Set the color ramps for the CRTC to the given values. */ + void + (*gamma_set)(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, + int size); + + /** + * Allocate the shadow area, delay the pixmap creation until needed + */ + void * + (*shadow_allocate) (xf86CrtcPtr crtc, int width, int height); + + /** + * Create shadow pixmap for rotation support + */ + PixmapPtr + (*shadow_create) (xf86CrtcPtr crtc, void *data, int width, int height); + + /** + * Destroy shadow pixmap + */ + void + (*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data); + + /** + * Set cursor colors + */ + void + (*set_cursor_colors) (xf86CrtcPtr crtc, int bg, int fg); + + /** + * Set cursor position + */ + void + (*set_cursor_position) (xf86CrtcPtr crtc, int x, int y); + + /** + * Show cursor + */ + void + (*show_cursor) (xf86CrtcPtr crtc); + + /** + * Hide cursor + */ + void + (*hide_cursor) (xf86CrtcPtr crtc); + + /** + * Load monochrome image + */ + void + (*load_cursor_image) (xf86CrtcPtr crtc, CARD8 *image); + + /** + * Load ARGB image + */ + void + (*load_cursor_argb) (xf86CrtcPtr crtc, CARD32 *image); + + /** + * Clean up driver-specific bits of the crtc + */ + void + (*destroy) (xf86CrtcPtr crtc); +} xf86CrtcFuncsRec, *xf86CrtcFuncsPtr; + +struct _xf86Crtc { + /** + * Associated ScrnInfo + */ + ScrnInfoPtr scrn; + + /** + * Active state of this CRTC + * + * Set when this CRTC is driving one or more outputs + */ + Bool enabled; + + /** + * Active mode + * + * This reflects the mode as set in the CRTC currently + * It will be cleared when the VT is not active or + * during server startup + */ + DisplayModeRec mode; + Rotation rotation; + PixmapPtr rotatedPixmap; + void *rotatedData; + + /** + * Position on screen + * + * Locates this CRTC within the frame buffer + */ + int x, y; + + /** + * Desired mode + * + * This is set to the requested mode, independent of + * whether the VT is active. In particular, it receives + * the startup configured mode and saves the active mode + * on VT switch. + */ + DisplayModeRec desiredMode; + Rotation desiredRotation; + int desiredX, desiredY; + + /** crtc-specific functions */ + const xf86CrtcFuncsRec *funcs; + + /** + * Driver private + * + * Holds driver-private information + */ + void *driver_private; + +#ifdef RANDR_12_INTERFACE + /** + * RandR crtc + * + * When RandR 1.2 is available, this + * points at the associated crtc object + */ + RRCrtcPtr randr_crtc; +#else + void *randr_crtc; +#endif + + /** + * Current cursor is ARGB + */ + Bool cursor_argb; + /** + * Track whether cursor is within CRTC range + */ + Bool cursor_in_range; + /** + * Track state of cursor associated with this CRTC + */ + Bool cursor_shown; + + /** + * Current transformation matrix + */ + PictTransform crtc_to_framebuffer; + PictTransform framebuffer_to_crtc; + Bool transform_in_use; + /** + * Bounding box in screen space + */ + BoxRec bounds; +}; + +typedef struct _xf86OutputFuncs { + /** + * Called to allow the output a chance to create properties after the + * RandR objects have been created. + */ + void + (*create_resources)(xf86OutputPtr output); + + /** + * Turns the output on/off, or sets intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. If the + * mode is DPMSModeOff, the output must be disabled, as the DPLL may be + * disabled afterwards. + */ + void + (*dpms)(xf86OutputPtr output, + int mode); + + /** + * Saves the output's state for restoration on VT switch. + */ + void + (*save)(xf86OutputPtr output); + + /** + * Restore's the output's state at VT switch. + */ + void + (*restore)(xf86OutputPtr output); + + /** + * Callback for testing a video mode for a given output. + * + * This function should only check for cases where a mode can't be supported + * on the output specifically, and not represent generic CRTC limitations. + * + * \return MODE_OK if the mode is valid, or another MODE_* otherwise. + */ + int + (*mode_valid)(xf86OutputPtr output, + DisplayModePtr pMode); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows an output to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool + (*mode_fixup)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Callback for preparing mode changes on an output + */ + void + (*prepare)(xf86OutputPtr output); + + /** + * Callback for committing mode changes on an output + */ + void + (*commit)(xf86OutputPtr output); + + /** + * Callback for setting up a video mode after fixups have been made. + * + * This is only called while the output is disabled. The dpms callback + * must be all that's necessary for the output, to turn the output on + * after this function is called. + */ + void + (*mode_set)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Probe for a connected output, and return detect_status. + */ + xf86OutputStatus + (*detect)(xf86OutputPtr output); + + /** + * Query the device for the modes it provides. + * + * This function may also update MonInfo, mm_width, and mm_height. + * + * \return singly-linked list of modes or NULL if no modes found. + */ + DisplayModePtr + (*get_modes)(xf86OutputPtr output); + +#ifdef RANDR_12_INTERFACE + /** + * Callback when an output's property has changed. + */ + Bool + (*set_property)(xf86OutputPtr output, + Atom property, + RRPropertyValuePtr value); +#endif + /** + * Clean up driver-specific bits of the output + */ + void + (*destroy) (xf86OutputPtr output); +} xf86OutputFuncsRec, *xf86OutputFuncsPtr; + +struct _xf86Output { + /** + * Associated ScrnInfo + */ + ScrnInfoPtr scrn; + + /** + * Currently connected crtc (if any) + * + * If this output is not in use, this field will be NULL. + */ + xf86CrtcPtr crtc; + + /** + * Possible CRTCs for this output as a mask of crtc indices + */ + CARD32 possible_crtcs; + + /** + * Possible outputs to share the same CRTC as a mask of output indices + */ + CARD32 possible_clones; + + /** + * Whether this output can support interlaced modes + */ + Bool interlaceAllowed; + + /** + * Whether this output can support double scan modes + */ + Bool doubleScanAllowed; + + /** + * List of available modes on this output. + * + * This should be the list from get_modes(), plus perhaps additional + * compatible modes added later. + */ + DisplayModePtr probed_modes; + + /** + * Options parsed from the related monitor section + */ + OptionInfoPtr options; + + /** + * Configured monitor section + */ + XF86ConfMonitorPtr conf_monitor; + + /** + * Desired initial position + */ + int initial_x, initial_y; + + /** + * Desired initial rotation + */ + Rotation initial_rotation; + + /** + * Current connection status + * + * This indicates whether a monitor is known to be connected + * to this output or not, or whether there is no way to tell + */ + xf86OutputStatus status; + + /** EDID monitor information */ + xf86MonPtr MonInfo; + + /** subpixel order */ + int subpixel_order; + + /** Physical size of the currently attached output device. */ + int mm_width, mm_height; + + /** Output name */ + char *name; + + /** output-specific functions */ + const xf86OutputFuncsRec *funcs; + + /** driver private information */ + void *driver_private; + + /** Whether to use the old per-screen Monitor config section */ + Bool use_screen_monitor; + +#ifdef RANDR_12_INTERFACE + /** + * RandR 1.2 output structure. + * + * When RandR 1.2 is available, this points at the associated + * RandR output structure and is created when this output is created + */ + RROutputPtr randr_output; +#else + void *randr_output; +#endif +}; + +typedef struct _xf86CrtcConfigFuncs { + /** + * Requests that the driver resize the screen. + * + * The driver is responsible for updating scrn->virtualX and scrn->virtualY. + * If the requested size cannot be set, the driver should leave those values + * alone and return FALSE. + * + * A naive driver that cannot reallocate the screen may simply change + * virtual[XY]. A more advanced driver will want to also change the + * devPrivate.ptr and devKind of the screen pixmap, update any offscreen + * pixmaps it may have moved, and change pScrn->displayWidth. + */ + Bool + (*resize)(ScrnInfoPtr scrn, + int width, + int height); +} xf86CrtcConfigFuncsRec, *xf86CrtcConfigFuncsPtr; + +typedef struct _xf86CrtcConfig { + int num_output; + xf86OutputPtr *output; + /** + * compat_output is used whenever we deal + * with legacy code that only understands a single + * output. pScrn->modes will be loaded from this output, + * adjust frame will whack this output, etc. + */ + int compat_output; + + int num_crtc; + xf86CrtcPtr *crtc; + + int minWidth, minHeight; + int maxWidth, maxHeight; + + /* For crtc-based rotation */ + DamagePtr rotation_damage; + Bool rotation_damage_registered; + + /* DGA */ + unsigned int dga_flags; + unsigned long dga_address; + DGAModePtr dga_modes; + int dga_nmode; + int dga_width, dga_height, dga_stride; + DisplayModePtr dga_save_mode; + + const xf86CrtcConfigFuncsRec *funcs; + + CreateScreenResourcesProcPtr CreateScreenResources; + + CloseScreenProcPtr CloseScreen; + + /* Cursor information */ + xf86CursorInfoPtr cursor_info; + CursorPtr cursor; + CARD8 *cursor_image; + Bool cursor_on; + CARD32 cursor_fg, cursor_bg; + + /** + * Options parsed from the related device section + */ + OptionInfoPtr options; + + Bool debug_modes; + + /* wrap screen BlockHandler for rotation */ + ScreenBlockHandlerProcPtr BlockHandler; + +} xf86CrtcConfigRec, *xf86CrtcConfigPtr; + +extern int xf86CrtcConfigPrivateIndex; + +#define XF86_CRTC_CONFIG_PTR(p) ((xf86CrtcConfigPtr) ((p)->privates[xf86CrtcConfigPrivateIndex].ptr)) + +/* + * Initialize xf86CrtcConfig structure + */ + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs); + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight); + +/* + * Crtc functions + */ +xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs); + +void +xf86CrtcDestroy (xf86CrtcPtr crtc); + + +/** + * Sets the given video mode on the given crtc + */ +Bool +xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + int x, int y); + +/* + * Assign crtc rotation during mode set + */ +Bool +xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation); + +/* + * Clean up rotation during CloseScreen + */ +void +xf86RotateCloseScreen (ScreenPtr pScreen); + +/** + * Return whether any output is assigned to the crtc + */ +Bool +xf86CrtcInUse (xf86CrtcPtr crtc); + +/* + * Output functions + */ +xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name); + +void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor); + +Bool +xf86OutputRename (xf86OutputPtr output, const char *name); + +void +xf86OutputDestroy (xf86OutputPtr output); + +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn, int maxX, int maxY); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn); + +Bool +xf86CrtcScreenInit (ScreenPtr pScreen); + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn, Bool canGrow); + +void +xf86DPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); + +Bool +xf86SaveScreen(ScreenPtr pScreen, int mode); + +void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn); + +DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired); + +Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation); + +/** + * Set the EDID information for the specified output + */ +void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon); + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output); + +xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus); + +/** + * Initialize dga for this screen + */ + +Bool +xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address); + +/** + * Re-initialize dga for this screen (as when the set of modes changes) + */ + +Bool +xf86DiDGAReInit (ScreenPtr pScreen); + +/* + * Set the subpixel order reported for the screen using + * the information from the outputs + */ + +void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen); + +/* + * Get a standard string name for a connector type + */ +char * +xf86ConnectorGetName(xf86ConnectorType connector); + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +Bool +xf86SetDesiredModes (ScrnInfoPtr pScrn); + +/** + * Initialize the CRTC-based cursor code. CRTC function vectors must + * contain relevant cursor setting functions. + * + * Driver should call this from ScreenInit function + */ +Bool +xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags); + +/** + * Called when anything on the screen is reconfigured. + * + * Reloads cursor images as needed, then adjusts cursor positions. + * + * Driver should call this from crtc commit function. + */ +void +xf86_reload_cursors (ScreenPtr screen); + +/** + * Called from EnterVT to turn the cursors back on + */ +void +xf86_show_cursors (ScrnInfoPtr scrn); + +/** + * Called by the driver to turn cursors off + */ +void +xf86_hide_cursors (ScrnInfoPtr scrn); + +/** + * Clean up CRTC-based cursor code. Driver must call this at CloseScreen time. + */ +void +xf86_cursors_fini (ScreenPtr screen); + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that. + * wraps xf86XVClipVideoHelper() + */ + +Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height); + +#endif /* _XF86CRTC_H_ */ diff --git a/driver/xf86-video-nv/compat/modes/xf86Cursors.c b/driver/xf86-video-nv/compat/modes/xf86Cursors.c new file mode 100644 index 000000000..b5101642b --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Cursors.c @@ -0,0 +1,646 @@ +/* + * Copyright © 2007 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" +#ifdef RENDER +#include "picturestr.h" +#endif +#include "cursorstr.h" + +/* + * Given a screen coordinate, rotate back to a cursor source coordinate + */ +static void +xf86_crtc_rotate_coord (Rotation rotation, + int width, + int height, + int x_dst, + int y_dst, + int *x_src, + int *y_src) +{ + int t; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + } + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + *x_src = x_dst; + *y_src = y_dst; +} + +/* + * Given a cursor source coordinate, rotate to a screen coordinate + */ +static void +xf86_crtc_rotate_coord_back (Rotation rotation, + int width, + int height, + int x_dst, + int y_dst, + int *x_src, + int *y_src) +{ + int t; + + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + } + *x_src = x_dst; + *y_src = y_dst; +} + +/* + * Convert an x coordinate to a position within the cursor bitmap + */ +static int +cursor_bitpos (int flags, int x, Bool mask) +{ + if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) + mask = !mask; + if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) + x = (x & ~3) | (3 - (x & 3)); + if (flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) + x = (x & ~7) | (7 - (x & 7)); + if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1) + x = (x << 1) + mask; + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8) + x = ((x & ~7) << 1) | (mask << 3) | (x & 7); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16) + x = ((x & ~15) << 1) | (mask << 4) | (x & 15); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32) + x = ((x & ~31) << 1) | (mask << 5) | (x & 31); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64) + x = ((x & ~63) << 1) | (mask << 6) | (x & 63); + return x; +} + +/* + * Fetch one bit from a cursor bitmap + */ +static CARD8 +get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) +{ + x = cursor_bitpos (flags, x, mask); + image += y * stride; + return (image[(x >> 3)] >> (x & 7)) & 1; +} + +/* + * Set one bit in a cursor bitmap + */ +static void +set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) +{ + x = cursor_bitpos (flags, x, mask); + image += y * stride; + image[(x >> 3)] |= 1 << (x & 7); +} + +/* + * Load a two color cursor into a driver that supports only ARGB cursors + */ +static void +xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; + int x, y; + int xin, yin; + int stride = cursor_info->MaxWidth >> 2; + int flags = cursor_info->Flags; + CARD32 bits; + +#ifdef ARGB_CURSOR + crtc->cursor_argb = FALSE; +#endif + + for (y = 0; y < cursor_info->MaxHeight; y++) + for (x = 0; x < cursor_info->MaxWidth; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + x, y, &xin, &yin); + if (get_bit (src, stride, flags, xin, yin, TRUE) == + ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) + { + if (get_bit (src, stride, flags, xin, yin, FALSE)) + bits = xf86_config->cursor_fg; + else + bits = xf86_config->cursor_bg; + } + else + bits = 0; + cursor_image[y * cursor_info->MaxWidth + x] = bits; + } + crtc->funcs->load_cursor_argb (crtc, cursor_image); +} + +/* + * Set the colors for a two-color cursor (ignore for ARGB cursors) + */ +static void +xf86_set_cursor_colors (ScrnInfoPtr scrn, int bg, int fg) +{ + ScreenPtr screen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + CursorPtr cursor = xf86_config->cursor; + int c; + CARD8 *bits = cursor ? cursor->devPriv[screen->myNum] : NULL; + + /* Save ARGB versions of these colors */ + xf86_config->cursor_fg = (CARD32) fg | 0xff000000; + xf86_config->cursor_bg = (CARD32) bg | 0xff000000; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled && !crtc->cursor_argb) + { + if (crtc->funcs->load_cursor_image) + crtc->funcs->set_cursor_colors (crtc, bg, fg); + else if (bits) + xf86_crtc_convert_cursor_to_argb (crtc, bits); + } + } +} + +static void +xf86_crtc_hide_cursor (xf86CrtcPtr crtc) +{ + if (crtc->cursor_shown) + { + crtc->funcs->hide_cursor (crtc); + crtc->cursor_shown = FALSE; + } +} + +_X_EXPORT void +xf86_hide_cursors (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + xf86_config->cursor_on = FALSE; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_hide_cursor (crtc); + } +} + +static void +xf86_crtc_show_cursor (xf86CrtcPtr crtc) +{ + if (!crtc->cursor_shown && crtc->cursor_in_range) + { + crtc->funcs->show_cursor (crtc); + crtc->cursor_shown = TRUE; + } +} + +_X_EXPORT void +xf86_show_cursors (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + xf86_config->cursor_on = TRUE; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_show_cursor (crtc); + } +} + +static void +xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + DisplayModePtr mode = &crtc->mode; + Bool in_range; + int dx, dy; + + /* + * Transform position of cursor on screen + */ + if (crtc->transform_in_use) + { + PictVector v; + v.vector[0] = IntToxFixed (x); v.vector[1] = IntToxFixed (y); v.vector[2] = IntToxFixed(1); + PictureTransformPoint (&crtc->framebuffer_to_crtc, &v); + x = xFixedToInt (v.vector[0]); y = xFixedToInt (v.vector[1]); + } + else + { + x -= crtc->x; + y -= crtc->y; + } + /* + * Transform position of cursor upper left corner + */ + xf86_crtc_rotate_coord_back (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + 0, 0, &dx, &dy); + x -= dx; + y -= dy; + + /* + * Disable the cursor when it is outside the viewport + */ + in_range = TRUE; + if (x >= mode->HDisplay || y >= mode->VDisplay || + x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight) + { + in_range = FALSE; + x = 0; + y = 0; + } + + crtc->cursor_in_range = in_range; + + if (in_range) + { + crtc->funcs->set_cursor_position (crtc, x, y); + xf86_crtc_show_cursor (crtc); + } + else + xf86_crtc_hide_cursor (crtc); +} + +static void +xf86_set_cursor_position (ScrnInfoPtr scrn, int x, int y) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* undo what xf86HWCurs did to the coordinates */ + x += scrn->frameX0; + y += scrn->frameY0; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_set_cursor_position (crtc, x, y); + } +} + +/* + * Load a two-color cursor into a crtc, performing rotation as needed + */ +static void +xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD8 *cursor_image; + +#ifdef ARGB_CURSOR + crtc->cursor_argb = FALSE; +#endif + + if (crtc->rotation == RR_Rotate_0) + cursor_image = src; + else + { + int x, y; + int xin, yin; + int stride = cursor_info->MaxWidth >> 2; + int flags = cursor_info->Flags; + + cursor_image = xf86_config->cursor_image; + memset(cursor_image, 0, cursor_info->MaxWidth * stride); + + for (y = 0; y < cursor_info->MaxHeight; y++) + for (x = 0; x < cursor_info->MaxWidth; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + x, y, &xin, &yin); + if (get_bit(src, stride, flags, xin, yin, FALSE)) + set_bit(cursor_image, stride, flags, x, y, FALSE); + if (get_bit(src, stride, flags, xin, yin, TRUE)) + set_bit(cursor_image, stride, flags, x, y, TRUE); + } + } + crtc->funcs->load_cursor_image (crtc, cursor_image); +} + +/* + * Load a cursor image into all active CRTCs + */ +static void +xf86_load_cursor_image (ScrnInfoPtr scrn, unsigned char *src) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + { + if (crtc->funcs->load_cursor_image) + xf86_crtc_load_cursor_image (crtc, src); + else if (crtc->funcs->load_cursor_argb) + xf86_crtc_convert_cursor_to_argb (crtc, src); + } + } +} + +static Bool +xf86_use_hw_cursor (ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + + if (xf86_config->cursor) + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = cursor; + ++cursor->refcnt; + + if (cursor->bits->width > cursor_info->MaxWidth || + cursor->bits->height> cursor_info->MaxHeight) + return FALSE; + + return TRUE; +} + +static Bool +xf86_use_hw_cursor_argb (ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + + if (xf86_config->cursor) + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = cursor; + ++cursor->refcnt; + + /* Make sure ARGB support is available */ + if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0) + return FALSE; + + if (cursor->bits->width > cursor_info->MaxWidth || + cursor->bits->height> cursor_info->MaxHeight) + return FALSE; + + return TRUE; +} + +static void +xf86_crtc_load_cursor_argb (xf86CrtcPtr crtc, CursorPtr cursor) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; + CARD32 *cursor_source = (CARD32 *) cursor->bits->argb; + int x, y; + int xin, yin; + CARD32 bits; + int source_width = cursor->bits->width; + int source_height = cursor->bits->height; + int image_width = cursor_info->MaxWidth; + int image_height = cursor_info->MaxHeight; + + for (y = 0; y < image_height; y++) + for (x = 0; x < image_width; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, image_width, image_height, + x, y, &xin, &yin); + if (xin < source_width && yin < source_height) + bits = cursor_source[yin * source_width + xin]; + else + bits = 0; + cursor_image[y * image_width + x] = bits; + } + + crtc->funcs->load_cursor_argb (crtc, cursor_image); +} + +static void +xf86_load_cursor_argb (ScrnInfoPtr scrn, CursorPtr cursor) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_load_cursor_argb (crtc, cursor); + } +} + +_X_EXPORT Bool +xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info; + + cursor_info = xf86CreateCursorInfoRec(); + if (!cursor_info) + return FALSE; + + xf86_config->cursor_image = xalloc (max_width * max_height * 4); + + if (!xf86_config->cursor_image) + { + xf86DestroyCursorInfoRec (cursor_info); + return FALSE; + } + + xf86_config->cursor_info = cursor_info; + + cursor_info->MaxWidth = max_width; + cursor_info->MaxHeight = max_height; + cursor_info->Flags = flags; + + cursor_info->SetCursorColors = xf86_set_cursor_colors; + cursor_info->SetCursorPosition = xf86_set_cursor_position; + cursor_info->LoadCursorImage = xf86_load_cursor_image; + cursor_info->HideCursor = xf86_hide_cursors; + cursor_info->ShowCursor = xf86_show_cursors; + cursor_info->UseHWCursor = xf86_use_hw_cursor; +#ifdef ARGB_CURSOR + if (flags & HARDWARE_CURSOR_ARGB) + { + cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb; + cursor_info->LoadCursorARGB = xf86_load_cursor_argb; + } +#endif + + xf86_config->cursor = NULL; + xf86_hide_cursors (scrn); + + return xf86InitCursor (screen, cursor_info); +} + +/** + * Called when anything on the screen is reconfigured. + * + * Reloads cursor images as needed, then adjusts cursor positions + */ + +_X_EXPORT void +xf86_reload_cursors (ScreenPtr screen) +{ + ScrnInfoPtr scrn; + xf86CrtcConfigPtr xf86_config; + xf86CursorInfoPtr cursor_info; + CursorPtr cursor; + int x, y; + + /* initial mode setting will not have set a screen yet */ + if (!screen) + return; + scrn = xf86Screens[screen->myNum]; + xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + /* make sure the cursor code has been initialized */ + cursor_info = xf86_config->cursor_info; + if (!cursor_info) + return; + + cursor = xf86_config->cursor; + GetSpritePosition (&x, &y); + if (!(cursor_info->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) + (*cursor_info->HideCursor)(scrn); + + if (cursor) + { +#ifdef ARGB_CURSOR + if (cursor->bits->argb && cursor_info->LoadCursorARGB) + (*cursor_info->LoadCursorARGB) (scrn, cursor); + else +#endif + (*cursor_info->LoadCursorImage)(cursor_info->pScrn, + cursor->devPriv[screen->myNum]); + + (*cursor_info->SetCursorPosition)(cursor_info->pScrn, x, y); + (*cursor_info->ShowCursor)(cursor_info->pScrn); + } +} + +/** + * Clean up CRTC-based cursor code + */ +_X_EXPORT void +xf86_cursors_fini (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (xf86_config->cursor_info) + { + xf86DestroyCursorInfoRec (xf86_config->cursor_info); + xf86_config->cursor_info = NULL; + } + if (xf86_config->cursor_image) + { + xfree (xf86_config->cursor_image); + xf86_config->cursor_image = NULL; + } + if (xf86_config->cursor) + { + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = NULL; + } +} diff --git a/driver/xf86-video-nv/compat/modes/xf86DiDGA.c b/driver/xf86-video-nv/compat/modes/xf86DiDGA.c new file mode 100644 index 000000000..f40d0abef --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86DiDGA.c @@ -0,0 +1,286 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86_OSproc.h" +#include "dgaproc.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "windowstr.h" + +static Bool +xf86_dga_get_modes (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + DGAModePtr modes, mode; + DisplayModePtr display_mode; + int bpp = scrn->bitsPerPixel >> 3; + int num; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + num++; + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + + if (!num) + return FALSE; + + modes = xalloc(num * sizeof(DGAModeRec)); + if (!modes) + return FALSE; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + mode = modes + num++; + + mode->mode = display_mode; + mode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; + if (display_mode->Flags & V_DBLSCAN) + mode->flags |= DGA_DOUBLESCAN; + if (display_mode->Flags & V_INTERLACE) + mode->flags |= DGA_INTERLACED; + mode->byteOrder = scrn->imageByteOrder; + mode->depth = scrn->depth; + mode->bitsPerPixel = scrn->bitsPerPixel; + mode->red_mask = scrn->mask.red; + mode->green_mask = scrn->mask.green; + mode->blue_mask = scrn->mask.blue; + mode->visualClass = (bpp == 1) ? PseudoColor : TrueColor; + mode->viewportWidth = display_mode->HDisplay; + mode->viewportHeight = display_mode->VDisplay; + mode->xViewportStep = (bpp == 3) ? 2 : 1; + mode->yViewportStep = 1; + mode->viewportFlags = DGA_FLIP_RETRACE; + mode->offset = 0; + mode->address = (unsigned char *) xf86_config->dga_address; + mode->bytesPerScanline = xf86_config->dga_stride; + mode->imageWidth = xf86_config->dga_width; + mode->imageHeight = xf86_config->dga_height; + mode->pixmapWidth = mode->imageWidth; + mode->pixmapHeight = mode->imageHeight; + mode->maxViewportX = mode->imageWidth - mode->viewportWidth; + mode->maxViewportY = mode->imageHeight - mode->viewportHeight; + + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + if (xf86_config->dga_modes) + xfree (xf86_config->dga_modes); + xf86_config->dga_nmode = num; + xf86_config->dga_modes = modes; + return TRUE; +} + +static Bool +xf86_dga_set_mode(ScrnInfoPtr scrn, DGAModePtr display_mode) +{ + ScreenPtr pScreen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!display_mode) + { + if (xf86_config->dga_save_mode) + { + xf86SwitchMode(pScreen, xf86_config->dga_save_mode); + xf86_config->dga_save_mode = NULL; + } + } + else + { + if (!xf86_config->dga_save_mode) + { + xf86_config->dga_save_mode = scrn->currentMode; + xf86SwitchMode(pScreen, display_mode->mode); + } + } + return TRUE; +} + +static int +xf86_dga_get_viewport(ScrnInfoPtr scrn) +{ + return 0; +} + +static void +xf86_dga_set_viewport(ScrnInfoPtr scrn, int x, int y, int flags) +{ + scrn->AdjustFrame(scrn->pScreen->myNum, x, y, flags); +} + +static Bool +xf86_dga_get_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr *ppDrawable, GCPtr *ppGC) +{ + ScreenPtr pScreen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + PixmapPtr pPixmap; + GCPtr pGC; + + pPixmap = GetScratchPixmapHeader (pScreen, xf86_config->dga_width, xf86_config->dga_height, + scrn->depth, scrn->bitsPerPixel, xf86_config->dga_stride, + (char *) scrn->memPhysBase + scrn->fbOffset); + if (!pPixmap) + return FALSE; + pGC = GetScratchGC (scrn->depth, pScreen); + if (!pGC) + { + FreeScratchPixmapHeader (pPixmap); + return FALSE; + } + *ppDrawable = &pPixmap->drawable; + *ppGC = pGC; + return TRUE; +} + +static void +xf86_dga_release_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr pDrawable, GCPtr pGC) +{ + FreeScratchGC (pGC); + FreeScratchPixmapHeader ((PixmapPtr) pDrawable); +} + +static void +xf86_dga_fill_rect(ScrnInfoPtr scrn, int x, int y, int w, int h, unsigned long color) +{ + GCPtr pGC; + DrawablePtr pDrawable; + XID vals[1]; + xRectangle r; + + if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC)) + return; + vals[0] = color; + ChangeGC (pGC, GCForeground, vals); + ValidateGC (pDrawable, pGC); + r.x = x; + r.y = y; + r.width = w; + r.height = h; + pGC->ops->PolyFillRect (pDrawable, pGC, 1, &r); + xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC); +} + +static void +xf86_dga_sync(ScrnInfoPtr scrn) +{ + ScreenPtr pScreen = scrn->pScreen; + WindowPtr pRoot = WindowTable [pScreen->myNum]; + char buffer[4]; + + pScreen->GetImage (&pRoot->drawable, 0, 0, 1, 1, ZPixmap, ~0L, buffer); +} + +static void +xf86_dga_blit_rect(ScrnInfoPtr scrn, int srcx, int srcy, int w, int h, int dstx, int dsty) +{ + DrawablePtr pDrawable; + GCPtr pGC; + + if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC)) + return; + ValidateGC (pDrawable, pGC); + pGC->ops->CopyArea (pDrawable, pDrawable, pGC, srcx, srcy, w, h, dstx, dsty); + xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC); +} + +static Bool +xf86_dga_open_framebuffer(ScrnInfoPtr scrn, + char **name, + unsigned char **mem, int *size, int *offset, int *flags) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + *size = xf86_config->dga_stride * xf86_config->dga_height; + *mem = (unsigned char *) (xf86_config->dga_address); + *offset = 0; + *flags = DGA_NEED_ROOT; + + return TRUE; +} + +static void +xf86_dga_close_framebuffer(ScrnInfoPtr scrn) +{ +} + +static DGAFunctionRec xf86_dga_funcs = { + xf86_dga_open_framebuffer, + xf86_dga_close_framebuffer, + xf86_dga_set_mode, + xf86_dga_set_viewport, + xf86_dga_get_viewport, + xf86_dga_sync, + xf86_dga_fill_rect, + xf86_dga_blit_rect, + NULL +}; + +_X_EXPORT Bool +xf86DiDGAReInit (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAReInitModes (pScreen, xf86_config->dga_modes, xf86_config->dga_nmode); +} + +_X_EXPORT Bool +xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + xf86_config->dga_flags = 0; + xf86_config->dga_address = dga_address; + xf86_config->dga_width = scrn->virtualX; + xf86_config->dga_height = scrn->virtualY; + xf86_config->dga_stride = scrn->displayWidth * scrn->bitsPerPixel >> 3; + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAInit(pScreen, &xf86_dga_funcs, xf86_config->dga_modes, xf86_config->dga_nmode); +} diff --git a/driver/xf86-video-nv/compat/modes/xf86EdidModes.c b/driver/xf86-video-nv/compat/modes/xf86EdidModes.c new file mode 100644 index 000000000..8b5e69d9a --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86EdidModes.c @@ -0,0 +1,491 @@ +/* + * Copyright 2006 Luc Verhaegen. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * @file This file covers code to convert a xf86MonPtr containing EDID-probed + * information into a list of modes, including applying monitor-specific + * quirks to fix broken EDID data. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include <X11/Xatom.h> +#include "property.h" +#include "propertyst.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include <string.h> +#include <math.h> + +/* + * Quirks to work around broken EDID data from various monitors. + */ + +typedef enum { + DDC_QUIRK_NONE = 0, + /* First detailed mode is bogus, prefer largest mode at 60hz */ + DDC_QUIRK_PREFER_LARGE_60 = 1 << 0, + /* 135MHz clock is too high, drop a bit */ + DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1, +} ddc_quirk_t; + +static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) +{ + /* Belinea 10 15 55 */ + if (memcmp (DDC->vendor.name, "MAX", 4) == 0 && + DDC->vendor.prod_id == 1516) + return TRUE; + + /* Acer AL1706 */ + if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && + DDC->vendor.prod_id == 44358) + return TRUE; + + /* Bug #10814: Samsung SyncMaster 225BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 596) + return TRUE; + + /* Bug #10545: Samsung SyncMaster 226BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 638) + return TRUE; + + return FALSE; +} + +static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC) +{ + /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */ + if (memcmp (DDC->vendor.name, "EPI", 4) == 0 && + DDC->vendor.prod_id == 59264) + return TRUE; + + return FALSE; +} + +typedef struct { + Bool (*detect) (int scrnIndex, xf86MonPtr DDC); + ddc_quirk_t quirk; + char *description; +} ddc_quirk_map_t; + +static const ddc_quirk_map_t ddc_quirks[] = { + { + quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60, + "Detailed timing is not preferred, use largest mode at 60Hz" + }, + { + quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH, + "Recommended 135MHz pixel clock is too high" + }, + { + NULL, DDC_QUIRK_NONE, + "No known quirks" + }, +}; + +/* + * TODO: + * - for those with access to the VESA DMT standard; review please. + */ +#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DRIVER +#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 + +static DisplayModeRec DDCEstablishedModes[17] = { + { MODEPREFIX("800x600"), 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ + { MODEPREFIX("800x600"), 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ + { MODEPREFIX("640x480"), 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ + { MODEPREFIX("640x480"), 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ + { MODEPREFIX("640x480"), 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */ + { MODEPREFIX("640x480"), 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ + { MODEPREFIX("720x400"), 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */ + { MODEPREFIX("720x400"), 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */ + { MODEPREFIX("1280x1024"), 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ + { MODEPREFIX("1024x768"), 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ + { MODEPREFIX("1024x768"), 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ + { MODEPREFIX("1024x768"), 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ + { MODEPREFIX("1024x768"), 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */ + { MODEPREFIX("832x624"), 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */ + { MODEPREFIX("800x600"), 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ + { MODEPREFIX("800x600"), 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ + { MODEPREFIX("1152x864"), 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ +}; + +static DisplayModePtr +DDCModesFromEstablished(int scrnIndex, struct established_timings *timing, + ddc_quirk_t quirks) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + CARD32 bits = (timing->t1) | (timing->t2 << 8) | + ((timing->t_manu & 0x80) << 9); + int i; + + for (i = 0; i < 17; i++) { + if (bits & (0x01 << i)) { + Mode = xf86DuplicateMode(&DDCEstablishedModes[i]); + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing, + ddc_quirk_t quirks) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + int i; + + for (i = 0; i < STD_TIMINGS; i++) { + if (timing[i].hsize && timing[i].vsize && timing[i].refresh) { + Mode = xf86CVTMode(timing[i].hsize, timing[i].vsize, + timing[i].refresh, FALSE, FALSE); + Mode->type = M_T_DRIVER; + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, + int preferred, ddc_quirk_t quirks) +{ + DisplayModePtr Mode; + + /* + * Refuse to create modes that are insufficiently large. 64 is a random + * number, maybe the spec says something about what the minimum is. In + * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe + * our parser is just being too aggresive there. + */ + if (timing->h_active < 64 || timing->v_active < 64) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring tiny %dx%d mode\n", __func__, + timing->h_active, timing->v_active); + return NULL; + } + + /* We don't do stereo */ + if (timing->stereo) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring: We don't handle stereo.\n", __func__); + return NULL; + } + + /* We only do seperate sync currently */ + if (timing->sync != 0x03) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: %dx%d Warning: We only handle seperate" + " sync.\n", __func__, timing->h_active, timing->v_active); + } + + Mode = xnfalloc(sizeof(DisplayModeRec)); + memset(Mode, 0, sizeof(DisplayModeRec)); + + Mode->type = M_T_DRIVER; + if (preferred) + Mode->type |= M_T_PREFERRED; + + if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) && + timing->clock == 135000000 ) + Mode->Clock = 108880; + else + Mode->Clock = timing->clock / 1000.0; + + Mode->HDisplay = timing->h_active; + Mode->HSyncStart = timing->h_active + timing->h_sync_off; + Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width; + Mode->HTotal = timing->h_active + timing->h_blanking; + + Mode->VDisplay = timing->v_active; + Mode->VSyncStart = timing->v_active + timing->v_sync_off; + Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width; + Mode->VTotal = timing->v_active + timing->v_blanking; + + xf86SetModeDefaultName(Mode); + + /* We ignore h/v_size and h/v_border for now. */ + + if (timing->interlaced) + Mode->Flags |= V_INTERLACE; + + if (timing->misc & 0x02) + Mode->Flags |= V_PVSYNC; + else + Mode->Flags |= V_NVSYNC; + + if (timing->misc & 0x01) + Mode->Flags |= V_PHSYNC; + else + Mode->Flags |= V_NHSYNC; + + return Mode; +} + +/* + * + */ +static void +DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes) +{ + DisplayModePtr Mode = Modes; + + if (!Monitor || !Modes) + return; + + /* set up the ranges for scanning through the modes */ + Monitor->nHsync = 1; + Monitor->hsync[0].lo = 1024.0; + Monitor->hsync[0].hi = 0.0; + + Monitor->nVrefresh = 1; + Monitor->vrefresh[0].lo = 1024.0; + Monitor->vrefresh[0].hi = 0.0; + + while (Mode) { + if (!Mode->HSync) + Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal); + + if (!Mode->VRefresh) + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + if (Mode->HSync < Monitor->hsync[0].lo) + Monitor->hsync[0].lo = Mode->HSync; + + if (Mode->HSync > Monitor->hsync[0].hi) + Monitor->hsync[0].hi = Mode->HSync; + + if (Mode->VRefresh < Monitor->vrefresh[0].lo) + Monitor->vrefresh[0].lo = Mode->VRefresh; + + if (Mode->VRefresh > Monitor->vrefresh[0].hi) + Monitor->vrefresh[0].hi = Mode->VRefresh; + + Mode = Mode->next; + } +} + +_X_EXPORT DisplayModePtr +xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) +{ + int preferred, i; + DisplayModePtr Modes = NULL, Mode; + ddc_quirk_t quirks; + + xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n", + DDC->vendor.name, DDC->vendor.prod_id); + quirks = DDC_QUIRK_NONE; + for (i = 0; ddc_quirks[i].detect; i++) + if (ddc_quirks[i].detect (scrnIndex, DDC)) + { + xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", + ddc_quirks[i].description); + quirks |= ddc_quirks[i].quirk; + } + + preferred = PREFERRED_TIMING_MODE(DDC->features.msc); + if (quirks & DDC_QUIRK_PREFER_LARGE_60) + preferred = 0; + + for (i = 0; i < DET_TIMINGS; i++) { + struct detailed_monitor_section *det_mon = &DDC->det_mon[i]; + + switch (det_mon->type) { + case DT: + Mode = DDCModeFromDetailedTiming(scrnIndex, + &det_mon->section.d_timings, + preferred, + quirks); + preferred = 0; + Modes = xf86ModesAdd(Modes, Mode); + break; + case DS_STD_TIMINGS: + Mode = DDCModesFromStandardTiming(scrnIndex, + det_mon->section.std_t, + quirks); + Modes = xf86ModesAdd(Modes, Mode); + break; + default: + break; + } + } + + /* Add established timings */ + Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks); + Modes = xf86ModesAdd(Modes, Mode); + + /* Add standard timings */ + Mode = DDCModesFromStandardTiming(scrnIndex, DDC->timings2, quirks); + Modes = xf86ModesAdd(Modes, Mode); + + if (quirks & DDC_QUIRK_PREFER_LARGE_60) + { + DisplayModePtr best = Modes; + for (Mode = Modes; Mode; Mode = Mode->next) + { + if (Mode == best) continue; + if (Mode->HDisplay * Mode->VDisplay > best->HDisplay * best->VDisplay) + { + best = Mode; + continue; + } + if (Mode->HDisplay * Mode->VDisplay == best->HDisplay * best->VDisplay) + { + double mode_refresh = xf86ModeVRefresh (Mode); + double best_refresh = xf86ModeVRefresh (best); + double mode_dist = fabs(mode_refresh - 60.0); + double best_dist = fabs(best_refresh - 60.0); + if (mode_dist < best_dist) + { + best = Mode; + continue; + } + } + } + if (best) + best->type |= M_T_PREFERRED; + } + return Modes; +} + +/* + * Fill out MonPtr with xf86MonPtr information. + */ +_X_EXPORT void +xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) +{ + DisplayModePtr Modes = NULL, Mode; + int i, clock; + Bool have_hsync = FALSE, have_vrefresh = FALSE, have_maxpixclock = FALSE; + + if (!Monitor || !DDC) + return; + + Monitor->DDC = DDC; + + Monitor->widthmm = 10 * DDC->features.hsize; + Monitor->heightmm = 10 * DDC->features.vsize; + + /* If this is a digital display, then we can use reduced blanking */ + if (DDC->features.input_type) + Monitor->reducedblanking = TRUE; + /* Allow the user to also enable this through config */ + + Modes = xf86DDCGetModes(scrnIndex, DDC); + + /* Skip EDID ranges if they were specified in the config file */ + have_hsync = (Monitor->nHsync != 0); + have_vrefresh = (Monitor->nVrefresh != 0); + have_maxpixclock = (Monitor->maxPixClock != 0); + + /* Go through the detailed monitor sections */ + for (i = 0; i < DET_TIMINGS; i++) { + switch (DDC->det_mon[i].type) { + case DS_RANGES: + if (!have_hsync) { + if (!Monitor->nHsync) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for horizontal sync\n"); + Monitor->hsync[Monitor->nHsync].lo = + DDC->det_mon[i].section.ranges.min_h; + Monitor->hsync[Monitor->nHsync].hi = + DDC->det_mon[i].section.ranges.max_h; + Monitor->nHsync++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using hsync ranges from config file\n"); + } + + if (!have_vrefresh) { + if (!Monitor->nVrefresh) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for vertical refresh\n"); + Monitor->vrefresh[Monitor->nVrefresh].lo = + DDC->det_mon[i].section.ranges.min_v; + Monitor->vrefresh[Monitor->nVrefresh].hi = + DDC->det_mon[i].section.ranges.max_v; + Monitor->nVrefresh++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using vrefresh ranges from config file\n"); + } + + clock = DDC->det_mon[i].section.ranges.max_clock * 1000; + if (!have_maxpixclock && clock > Monitor->maxPixClock) + Monitor->maxPixClock = clock; + + break; + default: + break; + } + } + + if (Modes) { + /* Print Modes */ + xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n"); + + Mode = Modes; + while (Mode) { + xf86PrintModeline(scrnIndex, Mode); + Mode = Mode->next; + } + + /* Do we still need ranges to be filled in? */ + if (!Monitor->nHsync || !Monitor->nVrefresh) + DDCGuessRangesFromModes(scrnIndex, Monitor, Modes); + + /* look for last Mode */ + Mode = Modes; + + while (Mode->next) + Mode = Mode->next; + + /* add to MonPtr */ + if (Monitor->Modes) { + Monitor->Last->next = Modes; + Modes->prev = Monitor->Last; + Monitor->Last = Mode; + } else { + Monitor->Modes = Modes; + Monitor->Last = Mode; + } + } +} diff --git a/driver/xf86-video-nv/compat/modes/xf86Modes.c b/driver/xf86-video-nv/compat/modes/xf86Modes.c new file mode 100644 index 000000000..f49c2921c --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Modes.c @@ -0,0 +1,661 @@ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86Modes.h" +#include "xf86Priv.h" + +extern XF86ConfigPtr xf86configptr; + +/** + * @file this file contains symbols from xf86Mode.c and friends that are static + * there but we still want to use. We need to come up with better API here. + */ + +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) +/** + * Calculates the horizontal sync rate of a mode. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT double +xf86ModeHSync(DisplayModePtr mode) +{ + double hsync = 0.0; + + if (mode->HSync > 0.0) + hsync = mode->HSync; + else if (mode->HTotal > 0) + hsync = (float)mode->Clock / (float)mode->HTotal; + + return hsync; +} + +/** + * Calculates the vertical refresh rate of a mode. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT double +xf86ModeVRefresh(DisplayModePtr mode) +{ + double refresh = 0.0; + + if (mode->VRefresh > 0.0) + refresh = mode->VRefresh; + else if (mode->HTotal > 0 && mode->VTotal > 0) { + refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; + if (mode->Flags & V_INTERLACE) + refresh *= 2.0; + if (mode->Flags & V_DBLSCAN) + refresh /= 2.0; + if (mode->VScan > 1) + refresh /= (float)(mode->VScan); + } + return refresh; +} + +_X_EXPORT int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->HDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->VDisplay; + default: + return 0; + } +} + +_X_EXPORT int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->VDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->HDisplay; + default: + return 0; + } +} + +/** Sets a default mode name of <width>x<height> on a mode. */ +_X_EXPORT void +xf86SetModeDefaultName(DisplayModePtr mode) +{ + if (mode->name != NULL) + xfree(mode->name); + + mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay); +} + +/* + * xf86SetModeCrtc + * + * Initialises the Crtc parameters for a mode. The initialisation includes + * adjustments for interlaced and double scan modes. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT void +xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) +{ + if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) + return; + + p->CrtcHDisplay = p->HDisplay; + p->CrtcHSyncStart = p->HSyncStart; + p->CrtcHSyncEnd = p->HSyncEnd; + p->CrtcHTotal = p->HTotal; + p->CrtcHSkew = p->HSkew; + p->CrtcVDisplay = p->VDisplay; + p->CrtcVSyncStart = p->VSyncStart; + p->CrtcVSyncEnd = p->VSyncEnd; + p->CrtcVTotal = p->VTotal; + if (p->Flags & V_INTERLACE) { + if (adjustFlags & INTERLACE_HALVE_V) { + p->CrtcVDisplay /= 2; + p->CrtcVSyncStart /= 2; + p->CrtcVSyncEnd /= 2; + p->CrtcVTotal /= 2; + } + /* Force interlaced modes to have an odd VTotal */ + /* maybe we should only do this when INTERLACE_HALVE_V is set? */ + p->CrtcVTotal |= 1; + } + + if (p->Flags & V_DBLSCAN) { + p->CrtcVDisplay *= 2; + p->CrtcVSyncStart *= 2; + p->CrtcVSyncEnd *= 2; + p->CrtcVTotal *= 2; + } + if (p->VScan > 1) { + p->CrtcVDisplay *= p->VScan; + p->CrtcVSyncStart *= p->VScan; + p->CrtcVSyncEnd *= p->VScan; + p->CrtcVTotal *= p->VScan; + } + p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); + p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); + p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); + p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); + + p->CrtcHAdjusted = FALSE; + p->CrtcVAdjusted = FALSE; +} + +/** + * Allocates and returns a copy of pMode, including pointers within pMode. + */ +_X_EXPORT DisplayModePtr +xf86DuplicateMode(DisplayModePtr pMode) +{ + DisplayModePtr pNew; + + pNew = xnfalloc(sizeof(DisplayModeRec)); + *pNew = *pMode; + pNew->next = NULL; + pNew->prev = NULL; + if (pNew->name == NULL) { + xf86SetModeDefaultName(pMode); + } else { + pNew->name = xnfstrdup(pMode->name); + } + + return pNew; +} + +/** + * Duplicates every mode in the given list and returns a pointer to the first + * mode. + * + * \param modeList doubly-linked mode list + */ +_X_EXPORT DisplayModePtr +xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr first = NULL, last = NULL; + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + DisplayModePtr new; + + new = xf86DuplicateMode(mode); + + /* Insert pNew into modeList */ + if (last) { + last->next = new; + new->prev = last; + } else { + first = new; + new->prev = NULL; + } + new->next = NULL; + last = new; + } + + return first; +} + +/** + * Returns true if the given modes should program to the same timings. + * + * This doesn't use Crtc values, as it might be used on ModeRecs without the + * Crtc values set. So, it's assumed that the other numbers are enough. + * + * This isn't in xf86Modes.c, but it might deserve to be there. + */ +_X_EXPORT Bool +xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2) +{ + if (pMode1->Clock == pMode2->Clock && + pMode1->HDisplay == pMode2->HDisplay && + pMode1->HSyncStart == pMode2->HSyncStart && + pMode1->HSyncEnd == pMode2->HSyncEnd && + pMode1->HTotal == pMode2->HTotal && + pMode1->HSkew == pMode2->HSkew && + pMode1->VDisplay == pMode2->VDisplay && + pMode1->VSyncStart == pMode2->VSyncStart && + pMode1->VSyncEnd == pMode2->VSyncEnd && + pMode1->VTotal == pMode2->VTotal && + pMode1->VScan == pMode2->VScan && + pMode1->Flags == pMode2->Flags) + { + return TRUE; + } else { + return FALSE; + } +} + +/* exact copy of xf86Mode.c */ +static void +add(char **p, char *new) +{ + *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); + strcat(*p, " "); + strcat(*p, new); +} + +/** + * Print out a modeline. + * + * Convenient VRefresh printing was added, though, compared to xf86Mode.c + */ +_X_EXPORT void +xf86PrintModeline(int scrnIndex,DisplayModePtr mode) +{ + char tmp[256]; + char *flags = xnfcalloc(1, 1); + + if (mode->HSkew) { + snprintf(tmp, 256, "hskew %i", mode->HSkew); + add(&flags, tmp); + } + if (mode->VScan) { + snprintf(tmp, 256, "vscan %i", mode->VScan); + add(&flags, tmp); + } + if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); + if (mode->Flags & V_CSYNC) add(&flags, "composite"); + if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); + if (mode->Flags & V_BCAST) add(&flags, "bcast"); + if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); + if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); + if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); + if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); + if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); + if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); +#if 0 + if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); +#endif + xf86DrvMsg(scrnIndex, X_INFO, + "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " + "(%.01f kHz)\n", + mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, + mode->HSyncStart, mode->HSyncEnd, mode->HTotal, + mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, + mode->VTotal, flags, xf86ModeHSync(mode)); + xfree(flags); +} +#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ + +/** + * Marks as bad any modes with unsupported flags. + * + * \param modeList doubly-linked or circular list of modes. + * \param flags flags supported by the driver. + * + * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) + mode->status = MODE_NO_INTERLACE; + if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) + mode->status = MODE_NO_DBLESCAN; + } +} + +/** + * Marks as bad any modes extending beyond the given max X, Y, or pitch. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (maxPitch > 0 && mode->HDisplay > maxPitch) + mode->status = MODE_BAD_WIDTH; + + if (maxX > 0 && mode->HDisplay > maxX) + mode->status = MODE_VIRTUAL_X; + + if (maxY > 0 && mode->VDisplay > maxY) + mode->status = MODE_VIRTUAL_Y; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes that aren't supported by the given monitor's + * hsync and vrefresh ranges. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, + MonPtr mon) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool bad; + int i; + + bad = TRUE; + for (i = 0; i < mon->nHsync; i++) { + if (xf86ModeHSync(mode) >= mon->hsync[i].lo && + xf86ModeHSync(mode) <= mon->hsync[i].hi) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_HSYNC; + + bad = TRUE; + for (i = 0; i < mon->nVrefresh; i++) { + if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo && + xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_VSYNC; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes extending beyond outside of the given clock ranges. + * + * \param modeList doubly-linked or circular list of modes. + * \param min pointer to minimums of clock ranges + * \param max pointer to maximums of clock ranges + * \param n_ranges number of ranges. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges) +{ + DisplayModePtr mode; + int i; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool good = FALSE; + for (i = 0; i < n_ranges; i++) { + if (mode->Clock >= min[i] && mode->Clock <= max[i]) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_CLOCK_RANGE; + } +} + +/** + * If the user has specified a set of mode names to use, mark as bad any modes + * not listed. + * + * The user mode names specified are prefixes to names of modes, so "1024x768" + * will match modes named "1024x768", "1024x768x75", "1024x768-good", but + * "1024x768x75" would only match "1024x768x75" from that list. + * + * MODE_BAD is used as the rejection flag, for lack of a better flag. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr mode; + + if (pScrn->display->modes[0] == NULL) + return; + + for (mode = modeList; mode != NULL; mode = mode->next) { + int i; + Bool good = FALSE; + + for (i = 0; pScrn->display->modes[i] != NULL; i++) { + if (strncmp(pScrn->display->modes[i], mode->name, + strlen(pScrn->display->modes[i])) == 0) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_BAD; + } +} + + +/** + * Frees any modes from the list with a status other than MODE_OK. + * + * \param modeList pointer to a doubly-linked or circular list of modes. + * \param verbose determines whether the reason for mode invalidation is + * printed. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose) +{ + DisplayModePtr mode; + + for (mode = *modeList; mode != NULL;) { + DisplayModePtr next = mode->next, first = *modeList; + + if (mode->status != MODE_OK) { + if (verbose) { + char *type = ""; + if (mode->type & M_T_BUILTIN) + type = "built-in "; + else if (mode->type & M_T_DEFAULT) + type = "default "; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using %smode \"%s\" (%s)\n", type, mode->name, + xf86ModeStatusToString(mode->status)); + } + xf86DeleteMode(modeList, mode); + } + + if (next == first) + break; + mode = next; + } +} + +/** + * Adds the new mode into the mode list, and returns the new list + * + * \param modes doubly-linked mode list. + */ +_X_EXPORT DisplayModePtr +xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) +{ + if (modes == NULL) + return new; + + if (new) { + DisplayModePtr mode = modes; + + while (mode->next) + mode = mode->next; + + mode->next = new; + new->prev = mode; + } + + return modes; +} + +/** + * Build a mode list from a list of config file modes + */ +static DisplayModePtr +xf86GetConfigModes (XF86ConfModeLinePtr conf_mode) +{ + DisplayModePtr head = NULL, prev = NULL, mode; + + for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) + { + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->name = xstrdup(conf_mode->ml_identifier); + if (!mode->name) + { + xfree (mode); + continue; + } + mode->type = 0; + mode->Clock = conf_mode->ml_clock; + mode->HDisplay = conf_mode->ml_hdisplay; + mode->HSyncStart = conf_mode->ml_hsyncstart; + mode->HSyncEnd = conf_mode->ml_hsyncend; + mode->HTotal = conf_mode->ml_htotal; + mode->VDisplay = conf_mode->ml_vdisplay; + mode->VSyncStart = conf_mode->ml_vsyncstart; + mode->VSyncEnd = conf_mode->ml_vsyncend; + mode->VTotal = conf_mode->ml_vtotal; + mode->Flags = conf_mode->ml_flags; + mode->HSkew = conf_mode->ml_hskew; + mode->VScan = conf_mode->ml_vscan; + + mode->prev = prev; + mode->next = NULL; + if (prev) + prev->next = mode; + else + head = mode; + prev = mode; + } + return head; +} + +/** + * Build a mode list from a monitor configuration + */ +_X_EXPORT DisplayModePtr +xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) +{ + DisplayModePtr modes = NULL; + XF86ConfModesLinkPtr modes_link; + + if (!conf_monitor) + return NULL; + + /* + * first we collect the mode lines from the UseModes directive + */ + for (modes_link = conf_monitor->mon_modes_sect_lst; + modes_link; + modes_link = modes_link->list.next) + { + /* If this modes link hasn't been resolved, go look it up now */ + if (!modes_link->ml_modes) + modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, + xf86configptr->conf_modes_lst); + if (modes_link->ml_modes) + modes = xf86ModesAdd (modes, + xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); + } + + return xf86ModesAdd (modes, + xf86GetConfigModes (conf_monitor->mon_modeline_lst)); +} + +/** + * Build a mode list containing all of the default modes + */ +_X_EXPORT DisplayModePtr +xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed) +{ + DisplayModePtr head = NULL, prev = NULL, mode; + int i; + + for (i = 0; xf86DefaultModes[i].name != NULL; i++) + { + DisplayModePtr defMode = &xf86DefaultModes[i]; + + if (!interlaceAllowed && (defMode->Flags & V_INTERLACE)) + continue; + if (!doubleScanAllowed && (defMode->Flags & V_DBLSCAN)) + continue; + + mode = xalloc(sizeof(DisplayModeRec)); + if (!mode) + continue; + memcpy(mode,&xf86DefaultModes[i],sizeof(DisplayModeRec)); + mode->name = xstrdup(xf86DefaultModes[i].name); + if (!mode->name) + { + xfree (mode); + continue; + } + mode->prev = prev; + mode->next = NULL; + if (prev) + prev->next = mode; + else + head = mode; + prev = mode; + } + return head; +} diff --git a/driver/xf86-video-nv/compat/modes/xf86Modes.h b/driver/xf86-video-nv/compat/modes/xf86Modes.h new file mode 100644 index 000000000..2bd4edeba --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Modes.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef _XF86MODES_H_ +#define _XF86MODES_H_ + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xorgVersion.h" +#include "edid.h" +#include "xf86Parser.h" +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif + +double xf86ModeHSync(DisplayModePtr mode); +double xf86ModeVRefresh(DisplayModePtr mode); + +int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation); + +int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation); + +DisplayModePtr xf86DuplicateMode(DisplayModePtr pMode); +DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn, + DisplayModePtr modeList); +void xf86SetModeDefaultName(DisplayModePtr mode); +void xf86SetModeCrtc(DisplayModePtr p, int adjustFlags); +Bool xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2); +void xf86PrintModeline(int scrnIndex,DisplayModePtr mode); +DisplayModePtr xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new); + +DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC); +DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, + Bool Reduced, Bool Interlaced); + +void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags); + +void +xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges); + +void +xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch); + +void +xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, + MonPtr mon); + +void +xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose); + +void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags); + +void +xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList); + +DisplayModePtr +xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor); + +DisplayModePtr +xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed); + +#endif /* _XF86MODES_H_ */ diff --git a/driver/xf86-video-nv/compat/modes/xf86RandR12.c b/driver/xf86-video-nv/compat/modes/xf86RandR12.c new file mode 100644 index 000000000..38435c924 --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86RandR12.c @@ -0,0 +1,1129 @@ +/* + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "os.h" +#include "mibank.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86DDC.h" +#include "mipointer.h" +#include "windowstr.h" +#include <randrstr.h> +#include <X11/extensions/render.h> + +#include "xf86Crtc.h" +#include "xf86RandR12.h" + +typedef struct _xf86RandR12Info { + int virtualX; + int virtualY; + int mmWidth; + int mmHeight; + int maxX; + int maxY; + Rotation rotation; /* current mode */ + Rotation supported_rotations; /* driver supported */ +} XF86RandRInfoRec, *XF86RandRInfoPtr; + +#ifdef RANDR_12_INTERFACE +static Bool xf86RandR12Init12 (ScreenPtr pScreen); +static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); +#endif + +static int xf86RandR12Index; +static int xf86RandR12Generation; + +#define XF86RANDRINFO(p) \ + ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr) + +static int +xf86RandR12ModeRefresh (DisplayModePtr mode) +{ + if (mode->VRefresh) + return (int) (mode->VRefresh + 0.5); + else + return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); +} + +static Bool +xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + int maxX = 0, maxY = 0; + + *rotations = randrp->supported_rotations; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + /* Re-probe the outputs for new monitors or modes */ + if (scrp->vtSema) + { + xf86ProbeOutputModes (scrp, 0, 0); + xf86SetScrnInfoModes (scrp); + xf86DiDGAReInit (pScreen); + } + + for (mode = scrp->modes; ; mode = mode->next) + { + int refresh = xf86RandR12ModeRefresh (mode); + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode == scrp->modes) + refresh0 = refresh; + pSize = RRRegisterSize (pScreen, + mode->HDisplay, mode->VDisplay, + randrp->mmWidth, randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh); + + if (xf86ModesEqual(mode, scrp->currentMode) && + mode->HDisplay == scrp->virtualX && + mode->VDisplay == scrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + } + if (mode->next == scrp->modes) + break; + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (scrp->currentMode->HDisplay != randrp->virtualX || + scrp->currentMode->VDisplay != randrp->virtualY) + { + pSize = RRRegisterSize (pScreen, + randrp->virtualX, randrp->virtualY, + randrp->mmWidth, + randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh0); + if (scrp->virtualX == randrp->virtualX && + scrp->virtualY == randrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); + } + } + + return TRUE; +} + +static Bool +xf86RandR12SetMode (ScreenPtr pScreen, + DisplayModePtr mode, + Bool useVirtual, + int mmWidth, + int mmHeight) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int oldWidth = pScreen->width; + int oldHeight = pScreen->height; + int oldmmWidth = pScreen->mmWidth; + int oldmmHeight = pScreen->mmHeight; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + DisplayModePtr currentMode = NULL; + Bool ret = TRUE; + PixmapPtr pspix = NULL; + + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); + if (useVirtual) + { + scrp->virtualX = randrp->virtualX; + scrp->virtualY = randrp->virtualY; + } + else + { + scrp->virtualX = mode->HDisplay; + scrp->virtualY = mode->VDisplay; + } + + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) + { + /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ + pScreen->width = scrp->virtualY; + pScreen->height = scrp->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } + else + { + pScreen->width = scrp->virtualX; + pScreen->height = scrp->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + if (scrp->currentMode == mode) { + /* Save current mode */ + currentMode = scrp->currentMode; + /* Reset, just so we ensure the drivers SwitchMode is called */ + scrp->currentMode = NULL; + } + /* + * We know that if the driver failed to SwitchMode to the rotated + * version, then it should revert back to it's prior mode. + */ + if (!xf86SwitchMode (pScreen, mode)) + { + ret = FALSE; + scrp->virtualX = pScreen->width = oldWidth; + scrp->virtualY = pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + scrp->currentMode = currentMode; + } + /* + * Get the new Screen pixmap ptr as SwitchMode might have called + * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back... + * Unfortunately. + */ + pspix = (*pScreen->GetScreenPixmap) (pScreen); + if (pspix->devPrivate.ptr) + scrp->pixmapPrivate = pspix->devPrivate; + + /* + * Make sure the layout is correct + */ + xf86ReconfigureLayout(); + + /* + * Make sure the whole screen is visible + */ + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); + return ret; +} + +_X_EXPORT Bool +xf86RandR12SetConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = randrp->rotation; + + randrp->rotation = rotation; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + miPointerPosition (&px, &py); + for (mode = scrp->modes; ; mode = mode->next) + { + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode->HDisplay == pSize->width && + mode->VDisplay == pSize->height && + (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) + break; + if (mode->next == scrp->modes) + { + if (pSize->width == randrp->virtualX && + pSize->height == randrp->virtualY) + { + mode = scrp->modes; + useVirtual = TRUE; + break; + } + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + return FALSE; + } + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { + randrp->rotation = oldRotation; + return FALSE; + } + + /* + * Move the cursor back where it belongs; SwitchMode repositions it + */ + if (pScreen == miPointerCurrentScreen ()) + { + px = (px >= pScreen->width ? (pScreen->width - 1) : px); + py = (py >= pScreen->height ? (pScreen->height - 1) : py); + + xf86SetViewport(pScreen, px, py); + + (*pScreen->SetCursorPosition) (pScreen, px, py, FALSE); + } + + return TRUE; +} + +static Bool +xf86RandR12ScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + WindowPtr pRoot = WindowTable[pScreen->myNum]; + PixmapPtr pScrnPix = (*pScreen->GetScreenPixmap)(pScreen); + Bool ret = FALSE; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); + + /* Let the driver update virtualX and virtualY */ + if (!(*config->funcs->resize)(pScrn, width, height)) + goto finish; + + ret = TRUE; + + pScreen->width = pScrnPix->drawable.width = width; + pScreen->height = pScrnPix->drawable.height = height; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + + xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1); + xf86SetViewport (pScreen, 0, 0); + +finish: + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); +#if RANDR_12_INTERFACE + if (WindowTable[pScreen->myNum] && ret) + RRScreenSizeNotify (pScreen); +#endif + return ret; +} + +_X_EXPORT Rotation +xf86RandR12GetRotation(ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + return randrp->rotation; +} + +_X_EXPORT Bool +xf86RandR12CreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + int width, height; + int mmWidth, mmHeight; +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + + /* + * Compute size of screen + */ + width = 0; height = 0; + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); + int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); + + if (crtc->enabled && crtc_width > width) + width = crtc_width; + if (crtc->enabled && crtc_height > height) + height = crtc_height; + } + + if (width && height) + { + /* + * Compute physical size of screen + */ + if (monitorResolution) + { + mmWidth = width * 25.4 / monitorResolution; + mmHeight = height * 25.4 / monitorResolution; + } + else + { + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (crtc && crtc->mode.HDisplay && + output->mm_width && output->mm_height) + { + /* + * If the output has a mode and a declared size, use that + * to scale the screen size + */ + DisplayModePtr mode = &crtc->mode; + mmWidth = output->mm_width * width / mode->HDisplay; + mmHeight = output->mm_height * height / mode->VDisplay; + } + else + { + /* + * Otherwise, just set the screen to 96dpi + */ + mmWidth = width * 25.4 / 96; + mmHeight = height * 25.4 / 96; + } + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting screen physical size to %d x %d\n", + mmWidth, mmHeight); + xf86RandR12ScreenSetSize (pScreen, + width, + height, + mmWidth, + mmHeight); + } + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + xf86CrtcSetScreenSubpixelOrder (pScreen); +#if RANDR_12_INTERFACE + if (xf86RandR12CreateScreenResources12 (pScreen)) + return TRUE; +#endif + return TRUE; +} + + +_X_EXPORT Bool +xf86RandR12Init (ScreenPtr pScreen) +{ + rrScrPrivPtr rp; + XF86RandRInfoPtr randrp; + +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + if (xf86RandR12Generation != serverGeneration) + { + xf86RandR12Index = AllocateScreenPrivateIndex(); + xf86RandR12Generation = serverGeneration; + } + + randrp = xalloc (sizeof (XF86RandRInfoRec)); + if (!randrp) + return FALSE; + + if (!RRScreenInit(pScreen)) + { + xfree (randrp); + return FALSE; + } + rp = rrGetScrPriv(pScreen); + rp->rrGetInfo = xf86RandR12GetInfo; + rp->rrSetConfig = xf86RandR12SetConfig; + + randrp->virtualX = -1; + randrp->virtualY = -1; + randrp->mmWidth = pScreen->mmWidth; + randrp->mmHeight = pScreen->mmHeight; + + randrp->rotation = RR_Rotate_0; /* initial rotated mode */ + + randrp->supported_rotations = RR_Rotate_0; + + randrp->maxX = randrp->maxY = 0; + + pScreen->devPrivates[xf86RandR12Index].ptr = randrp; + +#if RANDR_12_INTERFACE + if (!xf86RandR12Init12 (pScreen)) + return FALSE; +#endif + return TRUE; +} + +_X_EXPORT void +xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); +#if RANDR_12_INTERFACE + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int c; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + RRCrtcSetRotations (crtc->randr_crtc, rotations); + } +#endif + randrp->supported_rotations = rotations; +} + +_X_EXPORT void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) +{ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + + if (xf86RandR12Generation != serverGeneration || + XF86RANDRINFO(pScreen)->virtualX == -1) + { + *x = pScrn->virtualX; + *y = pScrn->virtualY; + } else { + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + *x = randrp->virtualX; + *y = randrp->virtualY; + } +} + +#if RANDR_12_INTERFACE + +#define FLAG_BITS (RR_HSyncPositive | \ + RR_HSyncNegative | \ + RR_VSyncPositive | \ + RR_VSyncNegative | \ + RR_Interlace | \ + RR_DoubleScan | \ + RR_CSync | \ + RR_CSyncPositive | \ + RR_CSyncNegative | \ + RR_HSkewPresent | \ + RR_BCast | \ + RR_PixelMultiplex | \ + RR_DoubleClock | \ + RR_ClockDivideBy2) + +static Bool +xf86RandRModeMatches (RRModePtr randr_mode, + DisplayModePtr mode) +{ +#if 0 + if (match_name) + { + /* check for same name */ + int len = strlen (mode->name); + if (randr_mode->mode.nameLength != len) return FALSE; + if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE; + } +#endif + + /* check for same timings */ + if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE; + if (randr_mode->mode.width != mode->HDisplay) return FALSE; + if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE; + if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE; + if (randr_mode->mode.hTotal != mode->HTotal) return FALSE; + if (randr_mode->mode.hSkew != mode->HSkew) return FALSE; + if (randr_mode->mode.height != mode->VDisplay) return FALSE; + if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE; + if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE; + if (randr_mode->mode.vTotal != mode->VTotal) return FALSE; + + /* check for same flags (using only the XF86 valid flag bits) */ + if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) + return FALSE; + + /* everything matches */ + return TRUE; +} + +static Bool +xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) +{ + ScreenPtr pScreen = randr_crtc->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RRModePtr randr_mode = NULL; + int x; + int y; + Rotation rotation; + int numOutputs; + RROutputPtr *randr_outputs; + RROutputPtr randr_output; + xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86OutputPtr output; + int i, j; + DisplayModePtr mode = &crtc->mode; + Bool ret; + + randr_outputs = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + if (!randr_outputs) + return FALSE; + x = crtc->x; + y = crtc->y; + rotation = crtc->rotation; + numOutputs = 0; + randr_mode = NULL; + for (i = 0; i < config->num_output; i++) + { + output = config->output[i]; + if (output->crtc == crtc) + { + randr_output = output->randr_output; + randr_outputs[numOutputs++] = randr_output; + /* + * We make copies of modes, so pointer equality + * isn't sufficient + */ + for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++) + { + RRModePtr m = (j < randr_output->numModes ? + randr_output->modes[j] : + randr_output->userModes[j-randr_output->numModes]); + + if (xf86RandRModeMatches (m, mode)) + { + randr_mode = m; + break; + } + } + } + } + ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, + rotation, numOutputs, randr_outputs); + DEALLOCATE_LOCAL(randr_outputs); + return ret; +} + +/* + * Convert a RandR mode to a DisplayMode + */ +static void +xf86RandRModeConvert (ScrnInfoPtr scrn, + RRModePtr randr_mode, + DisplayModePtr mode) +{ + mode->prev = NULL; + mode->next = NULL; + mode->name = NULL; + mode->status = MODE_OK; + mode->type = 0; + + mode->Clock = randr_mode->mode.dotClock / 1000; + + mode->HDisplay = randr_mode->mode.width; + mode->HSyncStart = randr_mode->mode.hSyncStart; + mode->HSyncEnd = randr_mode->mode.hSyncEnd; + mode->HTotal = randr_mode->mode.hTotal; + mode->HSkew = randr_mode->mode.hSkew; + + mode->VDisplay = randr_mode->mode.height; + mode->VSyncStart = randr_mode->mode.vSyncStart; + mode->VSyncEnd = randr_mode->mode.vSyncEnd; + mode->VTotal = randr_mode->mode.vTotal; + mode->VScan = 0; + + mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; + + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + +static Bool +xf86RandR12CrtcSet (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + RRModePtr randr_mode, + int x, + int y, + Rotation rotation, + int num_randr_outputs, + RROutputPtr *randr_outputs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = randr_crtc->devPrivate; + Bool changed = FALSE; + int o, ro; + xf86CrtcPtr *save_crtcs; + Bool save_enabled = crtc->enabled; + + save_crtcs = ALLOCATE_LOCAL(config->num_output * sizeof (xf86CrtcPtr)); + if ((randr_mode != NULL) != crtc->enabled) + changed = TRUE; + else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode)) + changed = TRUE; + + if (rotation != crtc->rotation) + changed = TRUE; + + if (x != crtc->x || y != crtc->y) + changed = TRUE; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + xf86CrtcPtr new_crtc; + + save_crtcs[o] = output->crtc; + + if (output->crtc == crtc) + new_crtc = NULL; + else + new_crtc = output->crtc; + for (ro = 0; ro < num_randr_outputs; ro++) + if (output->randr_output == randr_outputs[ro]) + { + new_crtc = crtc; + break; + } + if (new_crtc != output->crtc) + { + changed = TRUE; + output->crtc = new_crtc; + } + } + for (ro = 0; ro < num_randr_outputs; ro++) + if (randr_outputs[ro]->pendingProperties) + changed = TRUE; + + /* XXX need device-independent mode setting code through an API */ + if (changed) + { + crtc->enabled = randr_mode != NULL; + + if (randr_mode) + { + DisplayModeRec mode; + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + if (!xf86CrtcSetMode (crtc, &mode, rotation, x, y)) + { + crtc->enabled = save_enabled; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + output->crtc = save_crtcs[o]; + } + DEALLOCATE_LOCAL(save_crtcs); + return FALSE; + } + /* + * Save the last successful setting for EnterVT + */ + crtc->desiredMode = mode; + crtc->desiredRotation = rotation; + crtc->desiredX = x; + crtc->desiredY = y; + } + xf86DisableUnusedFunctions (pScrn); + } + DEALLOCATE_LOCAL(save_crtcs); + return xf86RandR12CrtcNotify (randr_crtc); +} + +static Bool +xf86RandR12CrtcSetGamma (ScreenPtr pScreen, + RRCrtcPtr randr_crtc) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (crtc->funcs->gamma_set == NULL) + return FALSE; + + if (!crtc->scrn->vtSema) + return TRUE; + + crtc->funcs->gamma_set(crtc, randr_crtc->gammaRed, randr_crtc->gammaGreen, + randr_crtc->gammaBlue, randr_crtc->gammaSize); + + return TRUE; +} + +static Bool +xf86RandR12OutputSetProperty (ScreenPtr pScreen, + RROutputPtr randr_output, + Atom property, + RRPropertyValuePtr value) +{ + xf86OutputPtr output = randr_output->devPrivate; + + /* If we don't have any property handler, then we don't care what the + * user is setting properties to. + */ + if (output->funcs->set_property == NULL) + return TRUE; + + /* + * This function gets called even when vtSema is FALSE, as + * drivers will need to remember the correct value to apply + * when the VT switch occurs + */ + return output->funcs->set_property(output, property, value); +} + +static Bool +xf86RandR12OutputValidateMode (ScreenPtr pScreen, + RROutputPtr randr_output, + RRModePtr randr_mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86OutputPtr output = randr_output->devPrivate; + DisplayModeRec mode; + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + /* + * This function may be called when vtSema is FALSE, so + * the underlying function must either avoid touching the hardware + * or return FALSE when vtSema is FALSE + */ + if (output->funcs->mode_valid (output, &mode) != MODE_OK) + return FALSE; + return TRUE; +} + +static void +xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) +{ +} + +/** + * Given a list of xf86 modes and a RandR Output object, construct + * RandR modes and assign them to the output + */ +static Bool +xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +{ + DisplayModePtr mode; + RRModePtr *rrmodes = NULL; + int nmode = 0; + int npreferred = 0; + Bool ret = TRUE; + int pref; + + for (mode = modes; mode; mode = mode->next) + nmode++; + + if (nmode) { + rrmodes = xalloc (nmode * sizeof (RRModePtr)); + + if (!rrmodes) + return FALSE; + nmode = 0; + + for (pref = 1; pref >= 0; pref--) { + for (mode = modes; mode; mode = mode->next) { + if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { + xRRModeInfo modeInfo; + RRModePtr rrmode; + + modeInfo.nameLength = strlen (mode->name); + modeInfo.width = mode->HDisplay; + modeInfo.dotClock = mode->Clock * 1000; + modeInfo.hSyncStart = mode->HSyncStart; + modeInfo.hSyncEnd = mode->HSyncEnd; + modeInfo.hTotal = mode->HTotal; + modeInfo.hSkew = mode->HSkew; + + modeInfo.height = mode->VDisplay; + modeInfo.vSyncStart = mode->VSyncStart; + modeInfo.vSyncEnd = mode->VSyncEnd; + modeInfo.vTotal = mode->VTotal; + modeInfo.modeFlags = mode->Flags; + + rrmode = RRModeGet (&modeInfo, mode->name); + if (rrmode) { + rrmodes[nmode++] = rrmode; + npreferred += pref; + } + } + } + } + } + + ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); + xfree (rrmodes); + return ret; +} + +/* + * Mirror the current mode configuration to RandR + */ +static Bool +xf86RandR12SetInfo12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RROutputPtr *clones; + RRCrtcPtr *crtcs; + int ncrtc; + int o, c, l; + RRCrtcPtr randr_crtc; + int nclone; + + clones = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + crtcs = ALLOCATE_LOCAL (config->num_crtc * sizeof (RRCrtcPtr)); + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + ncrtc = 0; + for (c = 0; c < config->num_crtc; c++) + if (output->possible_crtcs & (1 << c)) + crtcs[ncrtc++] = config->crtc[c]->randr_crtc; + + if (output->crtc) + randr_crtc = output->crtc->randr_crtc; + else + randr_crtc = NULL; + + if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } + + RROutputSetPhysicalSize(output->randr_output, + output->mm_width, + output->mm_height); + xf86RROutputSetModes (output->randr_output, output->probed_modes); + + switch (output->status) { + case XF86OutputStatusConnected: + RROutputSetConnection (output->randr_output, RR_Connected); + break; + case XF86OutputStatusDisconnected: + RROutputSetConnection (output->randr_output, RR_Disconnected); + break; + case XF86OutputStatusUnknown: + RROutputSetConnection (output->randr_output, RR_UnknownConnection); + break; + } + + RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); + + /* + * Valid clones + */ + nclone = 0; + for (l = 0; l < config->num_output; l++) + { + xf86OutputPtr clone = config->output[l]; + + if (l != o && (output->possible_clones & (1 << l))) + clones[nclone++] = clone->randr_output; + } + if (!RROutputSetClones (output->randr_output, clones, nclone)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } + } + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return TRUE; +} + + + +/* + * Query the hardware for the current state, then mirror + * that to RandR + */ +static Bool +xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!pScrn->vtSema) + return TRUE; + xf86ProbeOutputModes (pScrn, 0, 0); + xf86SetScrnInfoModes (pScrn); + xf86DiDGAReInit (pScreen); + return xf86RandR12SetInfo12 (pScreen); +} + +static Bool +xf86RandR12CreateObjects12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + int o; + + if (!RRInit ()) + return FALSE; + + /* + * Configure crtcs + */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = RRCrtcCreate (pScreen, crtc); + RRCrtcGammaSetSize (crtc->randr_crtc, 256); + } + /* + * Configure outputs + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = RROutputCreate (pScreen, output->name, + strlen (output->name), + output); + + if (output->funcs->create_resources != NULL) + output->funcs->create_resources(output); + RRPostPendingProperties (output->randr_output); + } + return TRUE; +} + +static Bool +xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) +{ + int c; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + + RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight, + config->maxWidth, config->maxHeight); + return TRUE; +} + +/* + * Something happened within the screen configuration due + * to DGA, VidMode or hot key. Tell RandR + */ + +_X_EXPORT void +xf86RandR12TellChanged (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + + if (!randrp) + return; + xf86RandR12SetInfo12 (pScreen); + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + RRTellChanged (pScreen); +} + +static void +xf86RandR12PointerMoved (int scrnIndex, int x, int y) +{ +} + +static Bool +xf86RandR12Init12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + rrScrPrivPtr rp = rrGetScrPriv(pScreen); + + rp->rrGetInfo = xf86RandR12GetInfo12; + rp->rrScreenSetSize = xf86RandR12ScreenSetSize; + rp->rrCrtcSet = xf86RandR12CrtcSet; + rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; + rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; + rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; + rp->rrModeDestroy = xf86RandR12ModeDestroy; + rp->rrSetConfig = NULL; + pScrn->PointerMoved = xf86RandR12PointerMoved; + if (!xf86RandR12CreateObjects12 (pScreen)) + return FALSE; + + /* + * Configure output modes + */ + if (!xf86RandR12SetInfo12 (pScreen)) + return FALSE; + return TRUE; +} + +#endif + +_X_EXPORT Bool +xf86RandR12PreInit (ScrnInfoPtr pScrn) +{ + return TRUE; +} diff --git a/driver/xf86-video-nv/compat/modes/xf86RandR12.h b/driver/xf86-video-nv/compat/modes/xf86RandR12.h new file mode 100644 index 000000000..4fd855cf5 --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86RandR12.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _XF86_RANDR_H_ +#define _XF86_RANDR_H_ +#include <randrstr.h> +#include <X11/extensions/render.h> +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif + +Bool xf86RandR12CreateScreenResources (ScreenPtr pScreen); +Bool xf86RandR12Init(ScreenPtr pScreen); +void xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotation); +Bool xf86RandR12SetConfig(ScreenPtr pScreen, Rotation rotation, int rate, + RRScreenSizePtr pSize); +Rotation xf86RandR12GetRotation(ScreenPtr pScreen); +void xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y); +Bool xf86RandR12PreInit (ScrnInfoPtr pScrn); +void xf86RandR12TellChanged (ScreenPtr pScreen); + +#endif /* _XF86_RANDR_H_ */ diff --git a/driver/xf86-video-nv/compat/modes/xf86Rename.h b/driver/xf86-video-nv/compat/modes/xf86Rename.h new file mode 100644 index 000000000..b8c1d70ef --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Rename.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _XF86RENAME_H_ +#define _XF86RENAME_H_ + +#include "local_xf86Rename.h" + +#define xf86_cursors_fini XF86NAME(xf86_cursors_fini) +#define xf86_cursors_init XF86NAME(xf86_cursors_init) +#define xf86_hide_cursors XF86NAME(xf86_hide_cursors) +#define xf86_reload_cursors XF86NAME(xf86_reload_cursors) +#define xf86_show_cursors XF86NAME(xf86_show_cursors) +#define xf86ConnectorGetName XF86NAME(xf86ConnectorGetName) +#define xf86CrtcConfigInit XF86NAME(xf86CrtcConfigInit) +#define xf86CrtcConfigPrivateIndex XF86NAME(xf86CrtcConfigPrivateIndex) +#define xf86CrtcCreate XF86NAME(xf86CrtcCreate) +#define xf86CrtcDestroy XF86NAME(xf86CrtcDestroy) +#define xf86CrtcInUse XF86NAME(xf86CrtcInUse) +#define xf86CrtcRotate XF86NAME(xf86CrtcRotate) +#define xf86CrtcScreenInit XF86NAME(xf86CrtcScreenInit) +#define xf86CrtcSetMode XF86NAME(xf86CrtcSetMode) +#define xf86CrtcSetSizeRange XF86NAME(xf86CrtcSetSizeRange) +#define xf86CVTMode XF86NAME(xf86CVTMode) +#define xf86DDCMonitorSet XF86NAME(xf86DDCMonitorSet) +#define xf86DisableUnusedFunctions XF86NAME(xf86DisableUnusedFunctions) +#define xf86DPMSSet XF86NAME(xf86DPMSSet) +#define xf86DuplicateMode XF86NAME(xf86DuplicateMode) +#define xf86DuplicateModes XF86NAME(xf86DuplicateModes) +#define xf86GetDefaultModes XF86NAME(xf86GetDefaultModes) +#define xf86GetMonitorModes XF86NAME(xf86GetMonitorModes) +#define xf86InitialConfiguration XF86NAME(xf86InitialConfiguration) +#define xf86ModeHSync XF86NAME(xf86ModeHSync) +#define xf86ModesAdd XF86NAME(xf86ModesAdd) +#define xf86ModesEqual XF86NAME(xf86ModesEqual) +#define xf86ModeVRefresh XF86NAME(xf86ModeVRefresh) +#define xf86OutputCreate XF86NAME(xf86OutputCreate) +#define xf86OutputDestroy XF86NAME(xf86OutputDestroy) +#define xf86OutputGetEDID XF86NAME(xf86OutputGetEDID) +#define xf86OutputGetEDIDModes XF86NAME(xf86OutputGetEDIDModes) +#define xf86OutputRename XF86NAME(xf86OutputRename) +#define xf86OutputSetEDID XF86NAME(xf86OutputSetEDID) +#define xf86OutputUseScreenMonitor XF86NAME(xf86OutputUseScreenMonitor) +#define xf86PrintModeline XF86NAME(xf86PrintModeline) +#define xf86ProbeOutputModes XF86NAME(xf86ProbeOutputModes) +#define xf86PruneInvalidModes XF86NAME(xf86PruneInvalidModes) +#define xf86RotateCloseScreen XF86NAME(xf86RotateCloseScreen) +#define xf86SetModeCrtc XF86NAME(xf86SetModeCrtc) +#define xf86SetModeDefaultName XF86NAME(xf86SetModeDefaultName) +#define xf86SetScrnInfoModes XF86NAME(xf86SetScrnInfoModes) +#define xf86ValidateModesClocks XF86NAME(xf86ValidateModesClocks) +#define xf86ValidateModesFlags XF86NAME(xf86ValidateModesFlags) +#define xf86ValidateModesSize XF86NAME(xf86ValidateModesSize) +#define xf86ValidateModesSync XF86NAME(xf86ValidateModesSync) +#define xf86ValidateModesUserConfig XF86NAME(xf86ValidateModesUserConfig) +#define xf86DiDGAInit XF86NAME(xf86DiDGAInit) +#define xf86DiDGAReInit XF86NAME(xf86DiDGAReInit) +#define xf86DDCGetModes XF86NAME(xf86DDCGetModes) +#define xf86RandR12CreateScreenResources XF86NAME(xf86RandR12CreateScreenResources) +#define xf86RandR12GetOriginalVirtualSize XF86NAME(xf86RandR12GetOriginalVirtualSize) +#define xf86RandR12GetRotation XF86NAME(xf86RandR12GetRotation) +#define xf86RandR12Init XF86NAME(xf86RandR12Init) +#define xf86RandR12PreInit XF86NAME(xf86RandR12PreInit) +#define xf86RandR12SetConfig XF86NAME(xf86RandR12SetConfig) +#define xf86RandR12SetRotations XF86NAME(xf86RandR12SetRotations) +#define xf86SaveScreen XF86NAME(xf86SaveScreen) +#define xf86CrtcSetScreenSubpixelOrder XF86NAME(xf86CrtcSetScreenSubpixelOrder) +#define xf86ModeWidth XF86NAME(xf86ModeWidth) +#define xf86ModeHeight XF86NAME(xf86ModeHeight) +#define xf86OutputFindClosestMode XF86NAME(xf86OutputFindClosestMode) +#define xf86SetSingleMode XF86NAME(xf86SetSingleMode) +#define xf86SetDesiredModes XF86NAME(xf86SetDesiredModes) + +#endif /* _XF86RENAME_H_ */ diff --git a/driver/xf86-video-nv/compat/modes/xf86Rotate.c b/driver/xf86-video-nv/compat/modes/xf86Rotate.c new file mode 100644 index 000000000..380478f7f --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86Rotate.c @@ -0,0 +1,660 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "fb.h" +#include "windowstr.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" + +/* borrowed from composite extension, move to Render and publish? */ + +static VisualPtr +compGetWindowVisual (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VisualID vid = wVisual (pWin); + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].vid == vid) + return &pScreen->visuals[i]; + return 0; +} + +static PictFormatPtr +compWindowFormat (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + return PictureMatchVisual (pScreen, pWin->drawable.depth, + compGetWindowVisual (pWin)); +} + +#define F(x) IntToxFixed(x) + +static void +PictureTransformIdentity (PictTransformPtr matrix) +{ + int i; + memset (matrix, '\0', sizeof (PictTransform)); + for (i = 0; i < 3; i++) + matrix->matrix[i][i] = F(1); +} + +static Bool +PictureTransformMultiply (PictTransformPtr dst, PictTransformPtr l, PictTransformPtr r) +{ + PictTransform d; + int dx, dy; + int o; + + for (dy = 0; dy < 3; dy++) + for (dx = 0; dx < 3; dx++) + { + xFixed_48_16 v; + xFixed_32_32 partial; + v = 0; + for (o = 0; o < 3; o++) + { + partial = (xFixed_32_32) l->matrix[dy][o] * (xFixed_32_32) r->matrix[o][dx]; + v += partial >> 16; + } + if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16) + return FALSE; + d.matrix[dy][dx] = (xFixed) v; + } + *dst = d; + return TRUE; +} + +static void +PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = sx; + t->matrix[1][1] = sy; + t->matrix[2][2] = F (1); +} + +static xFixed +fixed_inverse (xFixed x) +{ + return (xFixed) ((((xFixed_48_16) F(1)) * F(1)) / x); +} + +static Bool +PictureTransformScale (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed sx, xFixed sy) +{ + PictTransform t; + + PictureTransformInitScale (&t, sx, sy); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + PictureTransformInitScale (&t, fixed_inverse (sx), fixed_inverse (sy)); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = c; + t->matrix[0][1] = -s; + t->matrix[1][0] = s; + t->matrix[1][1] = c; + t->matrix[2][2] = F (1); +} + +static Bool +PictureTransformRotate (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed c, xFixed s) +{ + PictTransform t; + PictureTransformInitRotate (&t, c, s); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + + PictureTransformInitRotate (&t, c, -s); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformInitTranslate (PictTransformPtr t, xFixed tx, xFixed ty) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = F (1); + t->matrix[0][2] = tx; + t->matrix[1][1] = F (1); + t->matrix[1][2] = ty; + t->matrix[2][2] = F (1); +} + +static Bool +PictureTransformTranslate (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed tx, xFixed ty) +{ + PictTransform t; + PictureTransformInitTranslate (&t, tx, ty); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + + PictureTransformInitTranslate (&t, -tx, -ty); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformBounds (BoxPtr b, PictTransformPtr matrix) +{ + PictVector v[4]; + int i; + int x1, y1, x2, y2; + + v[0].vector[0] = F (b->x1); v[0].vector[1] = F (b->y1); v[0].vector[2] = F(1); + v[1].vector[0] = F (b->x2); v[1].vector[1] = F (b->y1); v[1].vector[2] = F(1); + v[2].vector[0] = F (b->x2); v[2].vector[1] = F (b->y2); v[2].vector[2] = F(1); + v[3].vector[0] = F (b->x1); v[3].vector[1] = F (b->y2); v[3].vector[2] = F(1); + for (i = 0; i < 4; i++) + { + PictureTransformPoint (matrix, &v[i]); + x1 = xFixedToInt (v[i].vector[0]); + y1 = xFixedToInt (v[i].vector[1]); + x2 = xFixedToInt (xFixedCeil (v[i].vector[0])); + y2 = xFixedToInt (xFixedCeil (v[i].vector[1])); + if (i == 0) + { + b->x1 = x1; b->y1 = y1; + b->x2 = x2; b->y2 = y2; + } + else + { + if (x1 < b->x1) b->x1 = x1; + if (y1 < b->y1) b->y1 = y1; + if (x2 > b->x2) b->x2 = x2; + if (y2 > b->y2) b->y2 = y2; + } + } +} + +static Bool +PictureTransformIsIdentity(PictTransform *t) +{ + return ((t->matrix[0][0] == t->matrix[1][1]) && + (t->matrix[0][0] == t->matrix[2][2]) && + (t->matrix[0][0] != 0) && + (t->matrix[0][1] == 0) && + (t->matrix[0][2] == 0) && + (t->matrix[1][0] == 0) && + (t->matrix[1][2] == 0) && + (t->matrix[2][0] == 0) && + (t->matrix[2][1] == 0)); +} + +#define toF(x) ((float) (x) / 65536.0f) + +static void +PictureTransformErrorF (PictTransform *t) +{ + ErrorF ("{ { %f %f %f } { %f %f %f } { %f %f %f } }", + toF(t->matrix[0][0]), toF(t->matrix[0][1]), toF(t->matrix[0][2]), + toF(t->matrix[1][0]), toF(t->matrix[1][1]), toF(t->matrix[1][2]), + toF(t->matrix[2][0]), toF(t->matrix[2][1]), toF(t->matrix[2][2])); +} + +static Bool +PictureTransformIsInverse (char *where, PictTransform *a, PictTransform *b) +{ + PictTransform t; + + PictureTransformMultiply (&t, a, b); + if (!PictureTransformIsIdentity (&t)) + { + ErrorF ("%s: ", where); + PictureTransformErrorF (a); + ErrorF (" * "); + PictureTransformErrorF (b); + ErrorF (" = "); + PictureTransformErrorF (a); + ErrorF ("\n"); + return FALSE; + } + return TRUE; +} + +static void +xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) +{ + ScrnInfoPtr scrn = crtc->scrn; + ScreenPtr screen = scrn->pScreen; + WindowPtr root = WindowTable[screen->myNum]; + PixmapPtr dst_pixmap = crtc->rotatedPixmap; + PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); + int error; + PicturePtr src, dst; + int n = REGION_NUM_RECTS(region); + BoxPtr b = REGION_RECTS(region); + XID include_inferiors = IncludeInferiors; + + src = CreatePicture (None, + &root->drawable, + format, + CPSubwindowMode, + &include_inferiors, + serverClient, + &error); + if (!src) + return; + + dst = CreatePicture (None, + &dst_pixmap->drawable, + format, + 0L, + NULL, + serverClient, + &error); + if (!dst) + return; + + error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); + if (error) + return; + + while (n--) + { + BoxRec dst_box; + + dst_box = *b; + PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc); + CompositePicture (PictOpSrc, + src, NULL, dst, + dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, + dst_box.x2 - dst_box.x1, + dst_box.y2 - dst_box.y1); + b++; + } + FreePicture (src, None); + FreePicture (dst, None); +} + +static void +xf86CrtcDamageShadow (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + BoxRec damage_box; + RegionRec damage_region; + ScreenPtr pScreen = pScrn->pScreen; + + damage_box.x1 = crtc->x; + damage_box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); + damage_box.y1 = crtc->y; + damage_box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); + REGION_INIT (pScreen, &damage_region, &damage_box, 1); + DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + &damage_region); + REGION_UNINIT (pScreen, &damage_region); +} + +static void +xf86RotatePrepare (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotatedData && !crtc->rotatedPixmap) + { + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + crtc->rotatedData, + crtc->mode.HDisplay, + crtc->mode.VDisplay); + if (!xf86_config->rotation_damage_registered) + { + /* Hook damage to screen pixmap */ + DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = TRUE; + } + + xf86CrtcDamageShadow (crtc); + } + } +} + +static Bool +xf86RotateRedisplay(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + DamagePtr damage = xf86_config->rotation_damage; + RegionPtr region; + + if (!damage) + return FALSE; + xf86RotatePrepare (pScreen); + region = DamageRegion(damage); + if (REGION_NOTEMPTY(pScreen, region)) + { + int c; + SourceValidateProcPtr SourceValidate; + + /* + * SourceValidate is used by the software cursor code + * to pull the cursor off of the screen when reading + * bits from the frame buffer. Bypassing this function + * leaves the software cursor in place + */ + SourceValidate = pScreen->SourceValidate; + pScreen->SourceValidate = NULL; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotation != RR_Rotate_0 && crtc->enabled) + { + RegionRec crtc_damage; + + /* compute portion of damage that overlaps crtc */ + REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); + REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); + + /* update damaged region */ + if (REGION_NOTEMPTY(pScreen, &crtc_damage)) + xf86RotateCrtcRedisplay (crtc, &crtc_damage); + + REGION_UNINIT (pScreen, &crtc_damage); + } + } + pScreen->SourceValidate = SourceValidate; + DamageEmpty(damage); + } + return TRUE; +} + +static void +xf86RotateBlockHandler(int screenNum, pointer blockData, + pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ScrnInfoPtr pScrn = xf86Screens[screenNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + pScreen->BlockHandler = xf86_config->BlockHandler; + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + if (xf86RotateRedisplay(pScreen)) + { + /* Re-wrap if rotation is still happening */ + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; + } +} + +static void +xf86RotateDestroy (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + ScreenPtr pScreen = pScrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + /* Free memory from rotation */ + if (crtc->rotatedPixmap || crtc->rotatedData) + { + crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c]->rotatedPixmap || + xf86_config->crtc[c]->rotatedData) + return; + + /* + * Clean up damage structures when no crtcs are rotated + */ + if (xf86_config->rotation_damage) + { + /* Free damage structure */ + if (xf86_config->rotation_damage_registered) + { + DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = FALSE; + } + DamageDestroy (xf86_config->rotation_damage); + xf86_config->rotation_damage = NULL; + } +} + +_X_EXPORT void +xf86RotateCloseScreen (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + xf86RotateDestroy (xf86_config->crtc[c]); +} + +_X_EXPORT Bool +xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PictTransform crtc_to_fb, fb_to_crtc; + + PictureTransformIdentity (&crtc_to_fb); + PictureTransformIdentity (&fb_to_crtc); + PictureTransformIsInverse ("identity", &crtc_to_fb, &fb_to_crtc); + if (rotation != RR_Rotate_0) + { + xFixed rot_cos, rot_sin, rot_dx, rot_dy; + xFixed scale_x, scale_y, scale_dx, scale_dy; + int mode_w = crtc->mode.HDisplay; + int mode_h = crtc->mode.VDisplay; + + /* rotation */ + switch (rotation & 0xf) { + default: + case RR_Rotate_0: + rot_cos = F ( 1); rot_sin = F ( 0); + rot_dx = F ( 0); rot_dy = F ( 0); + break; + case RR_Rotate_90: + rot_cos = F ( 0); rot_sin = F ( 1); + rot_dx = F ( mode_h); rot_dy = F (0); + break; + case RR_Rotate_180: + rot_cos = F (-1); rot_sin = F ( 0); + rot_dx = F (mode_w); rot_dy = F ( mode_h); + break; + case RR_Rotate_270: + rot_cos = F ( 0); rot_sin = F (-1); + rot_dx = F ( 0); rot_dy = F ( mode_w); + break; + } + + PictureTransformRotate (&crtc_to_fb, &fb_to_crtc, rot_cos, rot_sin); + PictureTransformIsInverse ("rotate", &crtc_to_fb, &fb_to_crtc); + + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy); + PictureTransformIsInverse ("rotate translate", &crtc_to_fb, &fb_to_crtc); + + /* reflection */ + scale_x = F (1); + scale_dx = 0; + scale_y = F (1); + scale_dy = 0; + if (rotation & RR_Reflect_X) + { + scale_x = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) + scale_dx = F(mode_w); + else + scale_dx = F(mode_h); + } + if (rotation & RR_Reflect_Y) + { + scale_y = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) + scale_dy = F(mode_h); + else + scale_dy = F(mode_w); + } + + PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y); + PictureTransformIsInverse ("scale", &crtc_to_fb, &fb_to_crtc); + + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy); + PictureTransformIsInverse ("scale translate", &crtc_to_fb, &fb_to_crtc); + + } + + /* + * If the untranslated transformation is the identity, + * disable the shadow buffer + */ + if (PictureTransformIsIdentity (&crtc_to_fb)) + { + crtc->transform_in_use = FALSE; + PictureTransformInitTranslate (&crtc->crtc_to_framebuffer, + F (-crtc->x), F (-crtc->y)); + PictureTransformInitTranslate (&crtc->framebuffer_to_crtc, + F ( crtc->x), F ( crtc->y)); + xf86RotateDestroy (crtc); + } + else + { + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, crtc->x, crtc->y); + PictureTransformIsInverse ("offset", &crtc_to_fb, &fb_to_crtc); + + /* + * these are the size of the shadow pixmap, which + * matches the mode, not the pre-rotated copy in the + * frame buffer + */ + int width = mode->HDisplay; + int height = mode->VDisplay; + void *shadowData = crtc->rotatedData; + PixmapPtr shadow = crtc->rotatedPixmap; + int old_width = shadow ? shadow->drawable.width : 0; + int old_height = shadow ? shadow->drawable.height : 0; + + /* Allocate memory for rotation */ + if (old_width != width || old_height != height) + { + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + shadowData = crtc->funcs->shadow_allocate (crtc, width, height); + if (!shadowData) + goto bail1; + crtc->rotatedData = shadowData; + /* shadow will be damaged in xf86RotatePrepare */ + } + else + { + /* mark shadowed area as damaged so it will be repainted */ + xf86CrtcDamageShadow (crtc); + } + + if (!xf86_config->rotation_damage) + { + /* Create damage structure */ + xf86_config->rotation_damage = DamageCreate (NULL, NULL, + DamageReportNone, + TRUE, pScreen, pScreen); + if (!xf86_config->rotation_damage) + goto bail2; + + /* Wrap block handler */ + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; + } + if (0) + { + bail2: + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + bail1: + if (old_width && old_height) + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + NULL, + old_width, + old_height); + return FALSE; + } + crtc->transform_in_use = TRUE; + crtc->crtc_to_framebuffer = crtc_to_fb; + crtc->framebuffer_to_crtc = fb_to_crtc; + crtc->bounds.x1 = 0; + crtc->bounds.x2 = crtc->mode.HDisplay; + crtc->bounds.y1 = 0; + crtc->bounds.y2 = crtc->mode.VDisplay; + PictureTransformBounds (&crtc->bounds, &crtc_to_fb); + } + + /* All done */ + return TRUE; +} diff --git a/driver/xf86-video-nv/compat/modes/xf86cvt.c b/driver/xf86-video-nv/compat/modes/xf86cvt.c new file mode 100644 index 000000000..69ccc4259 --- /dev/null +++ b/driver/xf86-video-nv/compat/modes/xf86cvt.c @@ -0,0 +1,308 @@ +/* + * Copyright 2005-2006 Luc Verhaegen. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file This is a copy of xf86cvt.c from the X Server, for compatibility with + * old servers (pre-1.2). + */ + +/* + * The reason for having this function in a file of its own is + * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode + * code is shared directly. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86Modes.h" + +#include <string.h> + +/* + * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. + * + * These calculations are stolen from the CVT calculation spreadsheet written + * by Graham Loveridge. He seems to be claiming no copyright and there seems to + * be no license attached to this. He apparently just wants to see his name + * mentioned. + * + * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls + * + * Comments and structure corresponds to the comments and structure of the xls. + * This should ease importing of future changes to the standard (not very + * likely though). + * + * About margins; i'm sure that they are to be the bit between HDisplay and + * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and + * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking + * outside sync "margin" for some reason. Since we prefer seeing proper + * blanking instead of the overscan colour, and since the Crtc* values will + * probably get altered after us, we will disable margins altogether. With + * these calculations, Margins will plainly expand H/VDisplay, and we don't + * want that. -- libv + * + */ +_X_EXPORT DisplayModePtr +xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, + Bool Interlaced) +{ + DisplayModeRec *Mode = xnfalloc(sizeof(DisplayModeRec)); + + /* 1) top/bottom margin size (% of height) - default: 1.8 */ +#define CVT_MARGIN_PERCENTAGE 1.8 + + /* 2) character cell horizontal granularity (pixels) - default 8 */ +#define CVT_H_GRANULARITY 8 + + /* 4) Minimum vertical porch (lines) - default 3 */ +#define CVT_MIN_V_PORCH 3 + + /* 4) Minimum number of vertical back porch lines - default 6 */ +#define CVT_MIN_V_BPORCH 6 + + /* Pixel Clock step (kHz) */ +#define CVT_CLOCK_STEP 250 + + Bool Margins = FALSE; + float VFieldRate, HPeriod; + int HDisplayRnd, HMargin; + int VDisplayRnd, VMargin, VSync; + float Interlace; /* Please rename this */ + + memset(Mode, 0, sizeof(DisplayModeRec)); + + /* CVT default is 60.0Hz */ + if (!VRefresh) + VRefresh = 60.0; + + /* 1. Required field rate */ + if (Interlaced) + VFieldRate = VRefresh * 2; + else + VFieldRate = VRefresh; + + /* 2. Horizontal pixels */ + HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY); + + /* 3. Determine left and right borders */ + if (Margins) { + /* right margin is actually exactly the same as left */ + HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + HMargin -= HMargin % CVT_H_GRANULARITY; + } else + HMargin = 0; + + /* 4. Find total active pixels */ + Mode->HDisplay = HDisplayRnd + 2*HMargin; + + /* 5. Find number of lines per field */ + if (Interlaced) + VDisplayRnd = VDisplay / 2; + else + VDisplayRnd = VDisplay; + + /* 6. Find top and bottom margins */ + /* nope. */ + if (Margins) + /* top and bottom margins are equal again. */ + VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + else + VMargin = 0; + + Mode->VDisplay = VDisplay + 2*VMargin; + + /* 7. Interlace */ + if (Interlaced) + Interlace = 0.5; + else + Interlace = 0.0; + + /* Determine VSync Width from aspect ratio */ + if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) + VSync = 4; + else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) + VSync = 5; + else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) + VSync = 6; + else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) + VSync = 7; + else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)) + VSync = 7; + else /* Custom */ + VSync = 10; + + if (!Reduced) { /* simplified GTF calculation */ + + /* 4) Minimum time of vertical sync + back porch interval (µs) + * default 550.0 */ +#define CVT_MIN_VSYNC_BP 550.0 + + /* 3) Nominal HSync width (% of line period) - default 8 */ +#define CVT_HSYNC_PERCENTAGE 8 + + float HBlankPercentage; + int VSyncAndBackPorch, VBackPorch; + int HBlank; + + /* 8. Estimated Horizontal period */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / + (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace); + + /* 9. Find number of lines in sync + backporch */ + if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH)) + VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH; + else + VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1; + + /* 10. Find number of lines in back porch */ + VBackPorch = VSyncAndBackPorch - VSync; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace + + CVT_MIN_V_PORCH; + + /* 5) Definition of Horizontal blanking time limitation */ + /* Gradient (%/kHz) - default 600 */ +#define CVT_M_FACTOR 600 + + /* Offset (%) - default 40 */ +#define CVT_C_FACTOR 40 + + /* Blanking time scaling factor - default 128 */ +#define CVT_K_FACTOR 128 + + /* Scaling factor weighting - default 20 */ +#define CVT_J_FACTOR 20 + +#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256 +#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ + CVT_J_FACTOR + + /* 12. Find ideal blanking duty cycle from formula */ + HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0; + + /* 13. Blanking time */ + if (HBlankPercentage < 20) + HBlankPercentage = 20; + + HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage); + HBlank -= HBlank % (2*CVT_H_GRANULARITY); + + /* 14. Find total number of pixels in a line. */ + Mode->HTotal = Mode->HDisplay + HBlank; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + HBlank / 2; + + Mode->HSyncStart = Mode->HSyncEnd - + (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100; + Mode->HSyncStart += CVT_H_GRANULARITY - + Mode->HSyncStart % CVT_H_GRANULARITY; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + + } else { /* Reduced blanking */ + /* Minimum vertical blanking interval time (µs) - default 460 */ +#define CVT_RB_MIN_VBLANK 460.0 + + /* Fixed number of clocks for horizontal sync */ +#define CVT_RB_H_SYNC 32.0 + + /* Fixed number of clocks for horizontal blanking */ +#define CVT_RB_H_BLANK 160.0 + + /* Fixed number of lines for vertical front porch - default 3 */ +#define CVT_RB_VFPORCH 3 + + int VBILines; + + /* 8. Estimate Horizontal period. */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / + (VDisplayRnd + 2*VMargin); + + /* 9. Find number of lines in vertical blanking */ + VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1; + + /* 10. Check if vertical blanking is sufficient */ + if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH)) + VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines; + + /* 12. Find total number of pixels in a line */ + Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2; + Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + } + + /* 15/13. Find pixel clock frequency (kHz for xf86) */ + Mode->Clock = Mode->HTotal * 1000.0 / HPeriod; + Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP; + + /* 16/14. Find actual Horizontal Frequency (kHz) */ + Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal); + + /* 17/15. Find actual Field rate */ + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + /* 18/16. Find actual vertical frame frequency */ + /* ignore - just set the mode flag for interlaced */ + if (Interlaced) + Mode->VTotal *= 2; + + { + char Name[256]; + Name[0] = 0; + + snprintf(Name, 256, "%dx%d", HDisplay, VDisplay); + + Mode->name = xnfalloc(strlen(Name) + 1); + memcpy(Mode->name, Name, strlen(Name) + 1); + } + + if (Reduced) + Mode->Flags |= V_PHSYNC | V_NVSYNC; + else + Mode->Flags |= V_NHSYNC | V_PVSYNC; + + if (Interlaced) + Mode->Flags |= V_INTERLACE; + + return Mode; +} diff --git a/driver/xf86-video-nv/compat/parser/xf86Optrec.h b/driver/xf86-video-nv/compat/parser/xf86Optrec.h new file mode 100644 index 000000000..183b85720 --- /dev/null +++ b/driver/xf86-video-nv/compat/parser/xf86Optrec.h @@ -0,0 +1,112 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2001 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * This file contains the Option Record that is passed between the Parser, + * and Module setup procs. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifndef _xf86Optrec_h_ +#define _xf86Optrec_h_ +#include <stdio.h> + +/* + * all records that need to be linked lists should contain a GenericList as + * their first field. + */ +typedef struct generic_list_rec +{ + void *next; +} +GenericListRec, *GenericListPtr, *glp; + +/* + * All options are stored using this data type. + */ +typedef struct +{ + GenericListRec list; + char *opt_name; + char *opt_val; + int opt_used; + char *opt_comment; +} +XF86OptionRec, *XF86OptionPtr; + + +XF86OptionPtr xf86addNewOption(XF86OptionPtr head, char *name, char *val); +XF86OptionPtr xf86optionListDup(XF86OptionPtr opt); +void xf86optionListFree(XF86OptionPtr opt); +char *xf86optionName(XF86OptionPtr opt); +char *xf86optionValue(XF86OptionPtr opt); +XF86OptionPtr xf86newOption(char *name, char *value); +XF86OptionPtr xf86nextOption(XF86OptionPtr list); +XF86OptionPtr xf86findOption(XF86OptionPtr list, const char *name); +char *xf86findOptionValue(XF86OptionPtr list, const char *name); +int xf86findOptionBoolean (XF86OptionPtr, const char *, int); +XF86OptionPtr xf86optionListCreate(const char **options, int count, int used); +XF86OptionPtr xf86optionListMerge(XF86OptionPtr head, XF86OptionPtr tail); +char *xf86configStrdup (const char *s); +int xf86nameCompare (const char *s1, const char *s2); +char *xf86uLongToString(unsigned long i); +void xf86debugListOptions(XF86OptionPtr); +XF86OptionPtr xf86parseOption(XF86OptionPtr head); +void xf86printOptionList(FILE *fp, XF86OptionPtr list, int tabs); + + +#endif /* _xf86Optrec_h_ */ diff --git a/driver/xf86-video-nv/compat/parser/xf86Parser.h b/driver/xf86-video-nv/compat/parser/xf86Parser.h new file mode 100644 index 000000000..dc30823cc --- /dev/null +++ b/driver/xf86-video-nv/compat/parser/xf86Parser.h @@ -0,0 +1,484 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * This file contains the external interfaces for the XFree86 configuration + * file parser. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifndef _xf86Parser_h_ +#define _xf86Parser_h_ + +#include "xf86Optrec.h" + +#define HAVE_PARSER_DECLS + +typedef struct +{ + char *file_logfile; + char *file_rgbpath; + char *file_modulepath; + char *file_inputdevs; + char *file_fontpath; + char *file_comment; +} +XF86ConfFilesRec, *XF86ConfFilesPtr; + +/* Values for load_type */ +#define XF86_LOAD_MODULE 0 +#define XF86_LOAD_DRIVER 1 +#define XF86_DISABLE_MODULE 2 + +typedef struct +{ + GenericListRec list; + int load_type; + char *load_name; + XF86OptionPtr load_opt; + char *load_comment; + int ignore; +} +XF86LoadRec, *XF86LoadPtr; + +typedef struct +{ + XF86LoadPtr mod_load_lst; + XF86LoadPtr mod_disable_lst; + char *mod_comment; +} +XF86ConfModuleRec, *XF86ConfModulePtr; + +#define CONF_IMPLICIT_KEYBOARD "Implicit Core Keyboard" + +#define CONF_IMPLICIT_POINTER "Implicit Core Pointer" + +#define XF86CONF_PHSYNC 0x0001 +#define XF86CONF_NHSYNC 0x0002 +#define XF86CONF_PVSYNC 0x0004 +#define XF86CONF_NVSYNC 0x0008 +#define XF86CONF_INTERLACE 0x0010 +#define XF86CONF_DBLSCAN 0x0020 +#define XF86CONF_CSYNC 0x0040 +#define XF86CONF_PCSYNC 0x0080 +#define XF86CONF_NCSYNC 0x0100 +#define XF86CONF_HSKEW 0x0200 /* hskew provided */ +#define XF86CONF_BCAST 0x0400 +#define XF86CONF_CUSTOM 0x0800 /* timing numbers customized by editor */ +#define XF86CONF_VSCAN 0x1000 + +typedef struct +{ + GenericListRec list; + char *ml_identifier; + int ml_clock; + int ml_hdisplay; + int ml_hsyncstart; + int ml_hsyncend; + int ml_htotal; + int ml_vdisplay; + int ml_vsyncstart; + int ml_vsyncend; + int ml_vtotal; + int ml_vscan; + int ml_flags; + int ml_hskew; + char *ml_comment; +} +XF86ConfModeLineRec, *XF86ConfModeLinePtr; + +typedef struct +{ + GenericListRec list; + char *vp_identifier; + XF86OptionPtr vp_option_lst; + char *vp_comment; +} +XF86ConfVideoPortRec, *XF86ConfVideoPortPtr; + +typedef struct +{ + GenericListRec list; + char *va_identifier; + char *va_vendor; + char *va_board; + char *va_busid; + char *va_driver; + XF86OptionPtr va_option_lst; + XF86ConfVideoPortPtr va_port_lst; + char *va_fwdref; + char *va_comment; +} +XF86ConfVideoAdaptorRec, *XF86ConfVideoAdaptorPtr; + +#define CONF_MAX_HSYNC 8 +#define CONF_MAX_VREFRESH 8 + +typedef struct +{ + float hi, lo; +} +parser_range; + +typedef struct +{ + int red, green, blue; +} +parser_rgb; + +typedef struct +{ + GenericListRec list; + char *modes_identifier; + XF86ConfModeLinePtr mon_modeline_lst; + char *modes_comment; +} +XF86ConfModesRec, *XF86ConfModesPtr; + +typedef struct +{ + GenericListRec list; + char *ml_modes_str; + XF86ConfModesPtr ml_modes; +} +XF86ConfModesLinkRec, *XF86ConfModesLinkPtr; + +typedef struct +{ + GenericListRec list; + char *mon_identifier; + char *mon_vendor; + char *mon_modelname; + int mon_width; /* in mm */ + int mon_height; /* in mm */ + XF86ConfModeLinePtr mon_modeline_lst; + int mon_n_hsync; + parser_range mon_hsync[CONF_MAX_HSYNC]; + int mon_n_vrefresh; + parser_range mon_vrefresh[CONF_MAX_VREFRESH]; + float mon_gamma_red; + float mon_gamma_green; + float mon_gamma_blue; + XF86OptionPtr mon_option_lst; + XF86ConfModesLinkPtr mon_modes_sect_lst; + char *mon_comment; +} +XF86ConfMonitorRec, *XF86ConfMonitorPtr; + +#define CONF_MAXDACSPEEDS 4 +#define CONF_MAXCLOCKS 128 + +typedef struct +{ + GenericListRec list; + char *dev_identifier; + char *dev_vendor; + char *dev_board; + char *dev_chipset; + char *dev_busid; + char *dev_card; + char *dev_driver; + char *dev_ramdac; + int dev_dacSpeeds[CONF_MAXDACSPEEDS]; + int dev_videoram; + int dev_textclockfreq; + unsigned long dev_bios_base; + unsigned long dev_mem_base; + unsigned long dev_io_base; + char *dev_clockchip; + int dev_clocks; + int dev_clock[CONF_MAXCLOCKS]; + int dev_chipid; + int dev_chiprev; + int dev_irq; + int dev_screen; + XF86OptionPtr dev_option_lst; + char *dev_comment; +} +XF86ConfDeviceRec, *XF86ConfDevicePtr; + +typedef struct +{ + GenericListRec list; + char *mode_name; +} +XF86ModeRec, *XF86ModePtr; + +typedef struct +{ + GenericListRec list; + int disp_frameX0; + int disp_frameY0; + int disp_virtualX; + int disp_virtualY; + int disp_depth; + int disp_bpp; + char *disp_visual; + parser_rgb disp_weight; + parser_rgb disp_black; + parser_rgb disp_white; + XF86ModePtr disp_mode_lst; + XF86OptionPtr disp_option_lst; + char *disp_comment; +} +XF86ConfDisplayRec, *XF86ConfDisplayPtr; + +typedef struct +{ + XF86OptionPtr flg_option_lst; + char *flg_comment; +} +XF86ConfFlagsRec, *XF86ConfFlagsPtr; + +typedef struct +{ + GenericListRec list; + char *al_adaptor_str; + XF86ConfVideoAdaptorPtr al_adaptor; +} +XF86ConfAdaptorLinkRec, *XF86ConfAdaptorLinkPtr; + +typedef struct +{ + GenericListRec list; + char *scrn_identifier; + char *scrn_obso_driver; + int scrn_defaultdepth; + int scrn_defaultbpp; + int scrn_defaultfbbpp; + char *scrn_monitor_str; + XF86ConfMonitorPtr scrn_monitor; + char *scrn_device_str; + XF86ConfDevicePtr scrn_device; + XF86ConfAdaptorLinkPtr scrn_adaptor_lst; + XF86ConfDisplayPtr scrn_display_lst; + XF86OptionPtr scrn_option_lst; + char *scrn_comment; +} +XF86ConfScreenRec, *XF86ConfScreenPtr; + +typedef struct +{ + GenericListRec list; + char *inp_identifier; + char *inp_driver; + XF86OptionPtr inp_option_lst; + char *inp_comment; +} +XF86ConfInputRec, *XF86ConfInputPtr; + +typedef struct +{ + GenericListRec list; + XF86ConfInputPtr iref_inputdev; + char *iref_inputdev_str; + XF86OptionPtr iref_option_lst; +} +XF86ConfInputrefRec, *XF86ConfInputrefPtr; + +/* Values for adj_where */ +#define CONF_ADJ_OBSOLETE -1 +#define CONF_ADJ_ABSOLUTE 0 +#define CONF_ADJ_RIGHTOF 1 +#define CONF_ADJ_LEFTOF 2 +#define CONF_ADJ_ABOVE 3 +#define CONF_ADJ_BELOW 4 +#define CONF_ADJ_RELATIVE 5 + +typedef struct +{ + GenericListRec list; + int adj_scrnum; + XF86ConfScreenPtr adj_screen; + char *adj_screen_str; + XF86ConfScreenPtr adj_top; + char *adj_top_str; + XF86ConfScreenPtr adj_bottom; + char *adj_bottom_str; + XF86ConfScreenPtr adj_left; + char *adj_left_str; + XF86ConfScreenPtr adj_right; + char *adj_right_str; + int adj_where; + int adj_x; + int adj_y; + char *adj_refscreen; +} +XF86ConfAdjacencyRec, *XF86ConfAdjacencyPtr; + +typedef struct +{ + GenericListRec list; + char *inactive_device_str; + XF86ConfDevicePtr inactive_device; +} +XF86ConfInactiveRec, *XF86ConfInactivePtr; + +typedef struct +{ + GenericListRec list; + char *lay_identifier; + XF86ConfAdjacencyPtr lay_adjacency_lst; + XF86ConfInactivePtr lay_inactive_lst; + XF86ConfInputrefPtr lay_input_lst; + XF86OptionPtr lay_option_lst; + char *lay_comment; +} +XF86ConfLayoutRec, *XF86ConfLayoutPtr; + +typedef struct +{ + GenericListRec list; + char *vs_name; + char *vs_identifier; + XF86OptionPtr vs_option_lst; + char *vs_comment; +} +XF86ConfVendSubRec, *XF86ConfVendSubPtr; + +typedef struct +{ + GenericListRec list; + char *vnd_identifier; + XF86OptionPtr vnd_option_lst; + XF86ConfVendSubPtr vnd_sub_lst; + char *vnd_comment; +} +XF86ConfVendorRec, *XF86ConfVendorPtr; + +typedef struct +{ + GenericListRec list; + int buf_count; + int buf_size; + char *buf_flags; + char *buf_comment; +} +XF86ConfBuffersRec, *XF86ConfBuffersPtr; + +typedef struct +{ + char *dri_group_name; + int dri_group; + int dri_mode; + XF86ConfBuffersPtr dri_buffers_lst; + char *dri_comment; +} +XF86ConfDRIRec, *XF86ConfDRIPtr; + +typedef struct +{ + XF86OptionPtr ext_option_lst; + char *extensions_comment; +} +XF86ConfExtensionsRec, *XF86ConfExtensionsPtr; + +typedef struct +{ + XF86ConfFilesPtr conf_files; + XF86ConfModulePtr conf_modules; + XF86ConfFlagsPtr conf_flags; + XF86ConfVideoAdaptorPtr conf_videoadaptor_lst; + XF86ConfModesPtr conf_modes_lst; + XF86ConfMonitorPtr conf_monitor_lst; + XF86ConfDevicePtr conf_device_lst; + XF86ConfScreenPtr conf_screen_lst; + XF86ConfInputPtr conf_input_lst; + XF86ConfLayoutPtr conf_layout_lst; + XF86ConfVendorPtr conf_vendor_lst; + XF86ConfDRIPtr conf_dri; + XF86ConfExtensionsPtr conf_extensions; + char *conf_comment; +} +XF86ConfigRec, *XF86ConfigPtr; + +typedef struct +{ + int token; /* id of the token */ + char *name; /* pointer to the LOWERCASED name */ +} +xf86ConfigSymTabRec, *xf86ConfigSymTabPtr; + +/* + * prototypes for public functions + */ +extern const char *xf86openConfigFile (const char *, const char *, + const char *); +extern void xf86setBuiltinConfig(const char *config[]); +extern XF86ConfigPtr xf86readConfigFile (void); +extern void xf86closeConfigFile (void); +extern void xf86freeConfig (XF86ConfigPtr p); +extern int xf86writeConfigFile (const char *, XF86ConfigPtr); +XF86ConfDevicePtr xf86findDevice(const char *ident, XF86ConfDevicePtr p); +XF86ConfLayoutPtr xf86findLayout(const char *name, XF86ConfLayoutPtr list); +XF86ConfMonitorPtr xf86findMonitor(const char *ident, XF86ConfMonitorPtr p); +XF86ConfModesPtr xf86findModes(const char *ident, XF86ConfModesPtr p); +XF86ConfModeLinePtr xf86findModeLine(const char *ident, XF86ConfModeLinePtr p); +XF86ConfScreenPtr xf86findScreen(const char *ident, XF86ConfScreenPtr p); +XF86ConfInputPtr xf86findInput(const char *ident, XF86ConfInputPtr p); +XF86ConfInputPtr xf86findInputByDriver(const char *driver, XF86ConfInputPtr p); +XF86ConfVideoAdaptorPtr xf86findVideoAdaptor(const char *ident, + XF86ConfVideoAdaptorPtr p); + +GenericListPtr xf86addListItem(GenericListPtr head, GenericListPtr c_new); +int xf86itemNotSublist(GenericListPtr list_1, GenericListPtr list_2); + +int xf86pathIsAbsolute(const char *path); +int xf86pathIsSafe(const char *path); +char *xf86addComment(char *cur, char *add); + +#endif /* _xf86Parser_h_ */ diff --git a/driver/xf86-video-nv/src/g80_cursor.c b/driver/xf86-video-nv/src/g80_cursor.c index 07422e570..98a27362d 100644 --- a/driver/xf86-video-nv/src/g80_cursor.c +++ b/driver/xf86-video-nv/src/g80_cursor.c @@ -21,7 +21,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,36 +35,10 @@ #define CURSOR_PTR ((CARD32*)pNv->mem + pNv->videoRam * 256 - 0x1000) -static void G80SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) -{ - G80Ptr pNv = G80PTR(pScrn); - CARD32 *dst = CURSOR_PTR; - CARD32 *src = pNv->tmpCursor; - int i, j; - - fg |= 0xff000000; - bg |= 0xff000000; - - for(i = 0; i < 128; i++) { - CARD32 b = *src++; - CARD32 m = *src++; - - for(j = 0; j < 32; j++) { - if(m & 1) - *dst = (b & 1) ? fg : bg; - else - *dst = 0; - b >>= 1; - m >>= 1; - dst++; - } - } -} - -static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y) { - G80Ptr pNv = G80PTR(pScrn); - const int headOff = 0x1000*pNv->head; + G80Ptr pNv = G80PTR(crtc->scrn); + const int headOff = 0x1000*G80CrtcGetHead(crtc); x &= 0xffff; y &= 0xffff; @@ -73,113 +46,58 @@ static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) pNv->reg[(0x00647080 + headOff)/4] = 0; } -static void G80LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) -{ - G80Ptr pNv = G80PTR(pScrn); - memcpy(pNv->tmpCursor, bits, sizeof(pNv->tmpCursor)); -} - -static void G80HideCursor(ScrnInfoPtr pScrn) +void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src) { - G80Ptr pNv = G80PTR(pScrn); + G80Ptr pNv = G80PTR(crtc->scrn); + CARD32 *dst = CURSOR_PTR; - pNv->cursorVisible = FALSE; - G80DispHideCursor(G80PTR(pScrn), TRUE); + /* Assume cursor is 64x64 */ + memcpy(dst, src, 64 * 64 * 4); } -static void G80ShowCursor(ScrnInfoPtr pScrn) +Bool G80CursorAcquire(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; - pNv->cursorVisible = TRUE; - G80DispShowCursor(G80PTR(pScrn), TRUE); -} + if(!pNv->HWCursor) return TRUE; -static Bool G80UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) -{ - return TRUE; -} + /* Initialize the cursor on each head */ + for(i = 0; i < xf86_config->num_crtc; i++) { + const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]); -#ifdef ARGB_CURSOR -static Bool G80UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) -{ - if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64)) - return TRUE; + pNv->reg[(0x00610270+headOff)/4] = 0x2000; + while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); - return FALSE; -} - -static void G80LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) -{ - G80Ptr pNv = G80PTR(pScrn); - CARD32 *dst = CURSOR_PTR, *src = pCurs->bits->argb; - int y; - - for(y = 0; y < pCurs->bits->height; y++) { - memcpy(dst, src, pCurs->bits->width * 4); - memset(dst + pCurs->bits->width, 0, (64 - pCurs->bits->width) * 4); - src += pCurs->bits->width; - dst += 64; + pNv->reg[(0x00610270+headOff)/4] = 1; + while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000); } - memset(dst, 0, (64 - y) * 64 * 4); -} -#endif - -Bool G80CursorAcquire(G80Ptr pNv) -{ - const int headOff = 0x10 * pNv->head; - - if(!pNv->HWCursor) return TRUE; - - pNv->reg[(0x00610270+headOff)/4] = 0x2000; - while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); - - pNv->reg[(0x00610270+headOff)/4] = 1; - while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000); - return TRUE; } -void G80CursorRelease(G80Ptr pNv) +void G80CursorRelease(ScrnInfoPtr pScrn) { - const int headOff = 0x10 * pNv->head; + G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; if(!pNv->HWCursor) return; - pNv->reg[(0x00610270+headOff)/4] = 0; - while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); + /* Release the cursor on each head */ + for(i = 0; i < xf86_config->num_crtc; i++) { + const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]); + + pNv->reg[(0x00610270+headOff)/4] = 0; + while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); + } } Bool G80CursorInit(ScreenPtr pScreen) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - G80Ptr pNv = G80PTR(pScrn); - xf86CursorInfoPtr infoPtr; - - if(!pNv->HWCursor) - return TRUE; - - infoPtr = xf86CreateCursorInfoRec(); - if(!infoPtr) return FALSE; - - pNv->CursorInfo = infoPtr; - pNv->cursorVisible = FALSE; - - infoPtr->MaxWidth = infoPtr->MaxHeight = 64; - infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | - HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32; - infoPtr->SetCursorColors = G80SetCursorColors; - infoPtr->SetCursorPosition = G80SetCursorPosition; - infoPtr->LoadCursorImage = G80LoadCursorImage; - infoPtr->HideCursor = G80HideCursor; - infoPtr->ShowCursor = G80ShowCursor; - infoPtr->UseHWCursor = G80UseHWCursor; - -#ifdef ARGB_CURSOR - infoPtr->UseHWCursorARGB = G80UseHWCursorARGB; - infoPtr->LoadCursorARGB = G80LoadCursorARGB; -#endif - - return xf86InitCursor(pScreen, infoPtr); + return xf86_cursors_init(pScreen, 64, 64, + HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 | + HARDWARE_CURSOR_ARGB); } diff --git a/driver/xf86-video-nv/src/g80_cursor.h b/driver/xf86-video-nv/src/g80_cursor.h index 9cd56eead..4d81d803b 100644 --- a/driver/xf86-video-nv/src/g80_cursor.h +++ b/driver/xf86-video-nv/src/g80_cursor.h @@ -1,3 +1,7 @@ Bool G80CursorInit(ScreenPtr); -Bool G80CursorAcquire(G80Ptr); -void G80CursorRelease(G80Ptr); +Bool G80CursorAcquire(ScrnInfoPtr); +void G80CursorRelease(ScrnInfoPtr); + +/* CRTC cursor functions */ +void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y); +void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src); diff --git a/driver/xf86-video-nv/src/g80_dac.c b/driver/xf86-video-nv/src/g80_dac.c new file mode 100644 index 000000000..30413cd50 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_dac.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static void +G80DacSetPClk(xf86OutputPtr output, int pclk) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int orOff = 0x800 * pPriv->or; + + pNv->reg[(0x00614280+orOff)/4] = 0; +} + +static void +G80DacDPMSSet(xf86OutputPtr output, int mode) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int off = 0x800 * pPriv->or; + CARD32 tmp; + + /* + * DPMSModeOn everything on + * DPMSModeStandby hsync disabled, vsync enabled + * DPMSModeSuspend hsync enabled, vsync disabled + * DPMSModeOff sync disabled + */ + while(pNv->reg[(0x0061A004+off)/4] & 0x80000000); + + tmp = pNv->reg[(0x0061A004+off)/4]; + tmp &= ~0x7f; + tmp |= 0x80000000; + + if(mode == DPMSModeStandby || mode == DPMSModeOff) + tmp |= 1; + if(mode == DPMSModeSuspend || mode == DPMSModeOff) + tmp |= 4; + if(mode != DPMSModeOn) + tmp |= 0x10; + if(mode == DPMSModeOff) + tmp |= 0x40; + + pNv->reg[(0x0061A004+off)/4] = tmp; +} + +Bool +G80DacModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + G80OutputPrivPtr pPriv = output->driver_private; + const int dacOff = 0x80 * pPriv->or; + + if(!adjusted_mode) { + C(0x00000400 + dacOff, 0); + return; + } + + // This wouldn't be necessary, but the server is stupid and calls + // G80DacDPMSSet after the output is disconnected, even though the hardware + // turns it off automatically. + G80DacDPMSSet(output, DPMSModeOn); + + C(0x00000400 + dacOff, + (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40); + C(0x00000404 + dacOff, + (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 | + (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0); + + G80CrtcSetScale(output->crtc, adjusted_mode, G80_SCALE_OFF); +} + +/* + * Perform DAC load detection to determine if there is a connected display. + */ +static xf86OutputStatus +G80DacDetect(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; + + G80OutputPartnersDetect(output, pPriv->partner, pPriv->i2c); + return pPriv->cached_status; +} + +Bool +G80DacLoadDetect(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + G80Ptr pNv = G80PTR(pScrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int scrnIndex = pScrn->scrnIndex; + const int dacOff = 2048 * pPriv->or; + CARD32 load, tmp, tmp2; + + xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ", + pPriv->or); + + pNv->reg[(0x0061A010+dacOff)/4] = 0x00000001; + tmp2 = pNv->reg[(0x0061A004+dacOff)/4]; + pNv->reg[(0x0061A004+dacOff)/4] = 0x80150000; + while(pNv->reg[(0x0061A004+dacOff)/4] & 0x80000000); + tmp = pNv->architecture == 0x50 ? 420 : 340; + pNv->reg[(0x0061A00C+dacOff)/4] = tmp | 0x100000; + usleep(4500); + load = pNv->reg[(0x0061A00C+dacOff)/4]; + pNv->reg[(0x0061A00C+dacOff)/4] = 0; + pNv->reg[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2; + + // Use this DAC if all three channels show load. + if((load & 0x38000000) == 0x38000000) { + xf86ErrorF("found one!\n"); + return TRUE; + } + + xf86ErrorF("nothing.\n"); + return FALSE; +} + +static void +G80DacDestroy(xf86OutputPtr output) +{ + G80OutputDestroy(output); + + xfree(output->driver_private); + output->driver_private = NULL; +} + +static const xf86OutputFuncsRec G80DacOutputFuncs = { + .dpms = G80DacDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80OutputModeValid, + .mode_fixup = G80DacModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80DacModeSet, + .detect = G80DacDetect, + .get_modes = G80OutputGetDDCModes, + .destroy = G80DacDestroy, +}; + +xf86OutputPtr +G80CreateDac(ScrnInfoPtr pScrn, ORNum or) +{ + G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1); + xf86OutputPtr output; + char orName[5]; + + if(!pPriv) + return FALSE; + + snprintf(orName, 5, "VGA%i", or); + output = xf86OutputCreate(pScrn, &G80DacOutputFuncs, orName); + + pPriv->type = DAC; + pPriv->or = or; + pPriv->cached_status = XF86OutputStatusUnknown; + pPriv->set_pclk = G80DacSetPClk; + output->driver_private = pPriv; + output->interlaceAllowed = TRUE; + output->doubleScanAllowed = TRUE; + + return output; +} diff --git a/driver/xf86-video-nv/src/g80_exa.c b/driver/xf86-video-nv/src/g80_exa.c new file mode 100644 index 000000000..96dbc2178 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_exa.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "g80_type.h" +#include "g80_dma.h" +#include "g80_xaa.h" + +static void +waitMarker(ScreenPtr pScreen, int marker) +{ + G80Sync(xf86Screens[pScreen->myNum]); +} + +static Bool +setSrc(G80Ptr pNv, PixmapPtr pSrc) +{ + CARD32 depth; + + switch(pSrc->drawable.depth) { + case 8: depth = 0x000000f3; break; + case 15: depth = 0x000000f8; break; + case 16: depth = 0x000000e8; break; + case 24: depth = 0x000000e6; break; + case 32: depth = 0x000000cf; break; + default: return FALSE; + } + + G80DmaStart(pNv, 0x230, 2); + G80DmaNext (pNv, depth); + G80DmaNext (pNv, 0x00000001); + G80DmaStart(pNv, 0x244, 5); + G80DmaNext (pNv, exaGetPixmapPitch(pSrc)); + G80DmaNext (pNv, pSrc->drawable.width); + G80DmaNext (pNv, pSrc->drawable.height); + G80DmaNext (pNv, 0x00000000); + G80DmaNext (pNv, exaGetPixmapOffset(pSrc)); + + return TRUE; +} + +static Bool +setDst(G80Ptr pNv, PixmapPtr pDst) +{ + CARD32 depth, depth2; + + switch(pDst->drawable.depth) { + case 8: depth = 0x000000f3; depth2 = 3; break; + case 15: depth = 0x000000f8; depth2 = 1; break; + case 16: depth = 0x000000e8; depth2 = 0; break; + case 24: depth = 0x000000e6; depth2 = 2; break; + case 32: depth = 0x000000cf; depth2 = 2; break; + default: return FALSE; + } + + G80DmaStart(pNv, 0x200, 2); + G80DmaNext (pNv, depth); + G80DmaNext (pNv, 0x00000001); + G80DmaStart(pNv, 0x214, 5); + G80DmaNext (pNv, exaGetPixmapPitch(pDst)); + G80DmaNext (pNv, pDst->drawable.width); + G80DmaNext (pNv, pDst->drawable.height); + G80DmaNext (pNv, 0x00000000); + G80DmaNext (pNv, exaGetPixmapOffset(pDst)); + G80DmaStart(pNv, 0x2e8, 1); + G80DmaNext (pNv, depth2); + G80DmaStart(pNv, 0x584, 1); + G80DmaNext (pNv, depth); + G80SetClip(pNv, 0, 0, pDst->drawable.width, pDst->drawable.height); + + return TRUE; +} + +/* solid fills */ + +static Bool +prepareSolid(PixmapPtr pPixmap, + int alu, + Pixel planemask, + Pixel fg) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + if(pPixmap->drawable.depth > 24) return FALSE; + if(!setDst(pNv, pPixmap)) return FALSE; + G80DmaStart(pNv, 0x2ac, 1); + G80DmaNext (pNv, 1); + G80SetRopSolid(pNv, alu, planemask); + G80DmaStart(pNv, 0x580, 1); + G80DmaNext (pNv, 4); + G80DmaStart(pNv, 0x588, 1); + G80DmaNext (pNv, fg); + + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + return TRUE; +} + +static void +solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + G80DmaStart(pNv, 0x600, 4); + G80DmaNext (pNv, x1); + G80DmaNext (pNv, y1); + G80DmaNext (pNv, x2); + G80DmaNext (pNv, y2); + + if((x2 - x1) * (y2 - y1) >= 512) + G80DmaKickoff(pNv); +} + +static void +doneSolid(PixmapPtr pPixmap) +{ +} + +/* screen to screen copies */ + +static Bool +prepareCopy(PixmapPtr pSrcPixmap, + PixmapPtr pDstPixmap, + int dx, + int dy, + int alu, + Pixel planemask) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + if(!setSrc(pNv, pSrcPixmap)) return FALSE; + if(!setDst(pNv, pDstPixmap)) return FALSE; + G80DmaStart(pNv, 0x2ac, 1); + if(alu == GXcopy && planemask == ~0) { + G80DmaNext (pNv, 3); + } else { + G80DmaNext (pNv, 1); + G80SetRopSolid(pNv, alu, planemask); + } + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + return TRUE; +} + +static void +copy(PixmapPtr pDstPixmap, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + G80DmaStart(pNv, 0x110, 1); + G80DmaNext (pNv, 0); + G80DmaStart(pNv, 0x8b0, 12); + G80DmaNext (pNv, dstX); + G80DmaNext (pNv, dstY); + G80DmaNext (pNv, width); + G80DmaNext (pNv, height); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, srcX); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, srcY); + + if(width * height >= 512) + G80DmaKickoff(pNv); +} + +static void +doneCopy(PixmapPtr pDstPixmap) +{ +} + +/* composite */ + +static Bool +checkComposite(int op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst) +{ + return FALSE; +} + +/* upload to screen */ + +static Bool +upload(PixmapPtr pDst, + int x, + int y, + int w, + int h, + char *src, + int src_pitch) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + const int Bpp = pDst->drawable.bitsPerPixel >> 3; + int line_dwords = (w * Bpp + 3) / 4; + const Bool kickoff = w * h >= 512; + CARD32 depth; + + if(!setDst(pNv, pDst)) return FALSE; + switch(pDst->drawable.depth) { + case 8: depth = 0x000000f3; break; + case 15: depth = 0x000000f8; break; + case 16: depth = 0x000000e8; break; + case 24: depth = 0x000000e6; break; + case 32: depth = 0x000000cf; break; + default: return FALSE; + } + + G80SetClip(pNv, x, y, w, h); + G80DmaStart(pNv, 0x2ac, 1); + G80DmaNext (pNv, 3); + G80DmaStart(pNv, 0x800, 2); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, depth); + G80DmaStart(pNv, 0x838, 10); + G80DmaNext (pNv, (line_dwords * 4) / Bpp); + G80DmaNext (pNv, h); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, x); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, y); + + while(h-- > 0) { + int count = line_dwords; + char *p = src; + + while(count) { + int size = count > 1792 ? 1792 : count; + + G80DmaStart(pNv, 0x40000860, size); + memcpy(&pNv->dmaBase[pNv->dmaCurrent], p, size * 4); + + p += size * Bpp; + pNv->dmaCurrent += size; + + count -= size; + } + + src += src_pitch; + } + + if(kickoff) + G80DmaKickoff(pNv); + else + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + + return TRUE; +} + +/******************************************************************************/ + +Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn) +{ + G80Ptr pNv = G80PTR(pScrn); + ExaDriverPtr exa; + const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8); + + exa = pNv->exa = exaDriverAlloc(); + if(!exa) return FALSE; + + exa->exa_major = EXA_VERSION_MAJOR; + exa->exa_minor = EXA_VERSION_MINOR; + exa->memoryBase = pNv->mem; + exa->offScreenBase = 0; + exa->memorySize = pitch * pNv->offscreenHeight; + exa->pixmapOffsetAlign = 256; + exa->pixmapPitchAlign = 256; + exa->flags = EXA_OFFSCREEN_PIXMAPS; + exa->maxX = 8192; + exa->maxY = 8192; + + /**** Rendering ops ****/ + exa->PrepareSolid = prepareSolid; + exa->Solid = solid; + exa->DoneSolid = doneSolid; + exa->PrepareCopy = prepareCopy; + exa->Copy = copy; + exa->DoneCopy = doneCopy; + exa->CheckComposite = checkComposite; + //exa->PrepareComposite = prepareComposite; + //exa->Composite = composite; + //exa->DoneComposite = doneComposite; + exa->UploadToScreen = upload; + + exa->WaitMarker = waitMarker; + + return exaDriverInit(pScreen, exa); +} diff --git a/driver/xf86-video-nv/src/g80_exa.h b/driver/xf86-video-nv/src/g80_exa.h new file mode 100644 index 000000000..2f01af621 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_exa.h @@ -0,0 +1 @@ +Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn); diff --git a/driver/xf86-video-nv/src/g80_output.c b/driver/xf86-video-nv/src/g80_output.c new file mode 100644 index 000000000..1ec6a89af --- /dev/null +++ b/driver/xf86-video-nv/src/g80_output.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <strings.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) +{ + unsigned char *table2; + unsigned char headerSize, entries; + int i; + CARD16 a; + CARD32 b; + + /* Clear the i2c map to invalid */ + for(i = 0; i < 4; i++) + pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1; + + if(*(CARD16*)pNv->table1 != 0xaa55) goto fail; + + a = *(CARD16*)(pNv->table1 + 0x36); + table2 = (unsigned char*)pNv->table1 + a; + + if(table2[0] != 0x40) goto fail; + + b = *(CARD32*)(table2 + 6); + if(b != 0x4edcbdcb) goto fail; + + headerSize = table2[1]; + entries = table2[2]; + + for(i = 0; i < entries; i++) { + int type, port; + ORNum or; + + b = *(CARD32*)&table2[headerSize + 8*i]; + type = b & 0xf; + port = (b >> 4) & 0xf; + or = ffs((b >> 24) & 0xf) - 1; + + if(type == 0xe) break; + + if(type < 4) { + switch(type) { + case 0: /* CRT */ + if(pNv->i2cMap[port].dac != -1) { + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! DAC %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].dac, port); + } + pNv->i2cMap[port].dac = or; + break; + case 1: /* TV */ + /* Ignore TVs */ + break; + + case 2: /* TMDS */ + if(pNv->i2cMap[port].sor != -1) + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! SOR %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].sor, port); + pNv->i2cMap[port].sor = or; + break; + + case 3: /* LVDS */ + pNv->lvds.present = TRUE; + pNv->lvds.or = or; + break; + } + } + } + + xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n"); + if(pNv->lvds.present) + xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or); + for(i = 0; i < 4; i++) { + if(pNv->i2cMap[i].dac != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac); + if(pNv->i2cMap[i].sor != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor); + } + + return TRUE; + +fail: + xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. " + "Mode setting will probably fail!\n"); + return FALSE; +} + +static void G80_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + + pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1; +} + +static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + unsigned char val; + + val = pNv->reg[(0x0000E138+off)/4]; + *clock = !!(val & 1); + *data = !!(val & 2); +} + +static I2CBusPtr +G80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port) +{ + I2CBusPtr i2c; + + /* Allocate the I2C bus structure */ + i2c = xf86CreateI2CBusRec(); + if(!i2c) return NULL; + + i2c->BusName = strdup(name); + i2c->scrnIndex = pScrn->scrnIndex; + i2c->I2CPutBits = G80_I2CPutBits; + i2c->I2CGetBits = G80_I2CGetBits; + i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + i2c->StartTimeout = 550; + i2c->BitTimeout = 40; + i2c->ByteTimeout = 40; + i2c->AcknTimeout = 40; + i2c->DriverPrivate.val = port; + + if(xf86I2CBusInit(i2c)) { + return i2c; + } else { + xfree(i2c); + return NULL; + } +} + +void +G80OutputSetPClk(xf86OutputPtr output, int pclk) +{ + G80OutputPrivPtr pPriv = output->driver_private; + if(pPriv->set_pclk) + pPriv->set_pclk(output, pclk); +} + +int +G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + if(mode->Clock > 400000) + return MODE_CLOCK_HIGH; + if(mode->Clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +void +G80OutputPrepare(xf86OutputPtr output) +{ +} + +void +G80OutputCommit(xf86OutputPtr output) +{ +} + +static xf86MonPtr +ProbeDDC(I2CBusPtr i2c) +{ + ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex]; + G80Ptr pNv = G80PTR(pScrn); + xf86MonPtr monInfo = NULL; + const int bus = i2c->DriverPrivate.val, off = bus * 0x18; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Probing for EDID on I2C bus %i...\n", bus); + pNv->reg[(0x0000E138+off)/4] = 7; + /* Should probably use xf86OutputGetEDID here */ + monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c); + pNv->reg[(0x0000E138+off)/4] = 3; + + if(monInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "DDC detected a %s:\n", monInfo->features.input_type ? + "DFP" : "CRT"); + xf86PrintEDID(monInfo); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); + } + + return monInfo; +} + +/* + * Read an EDID from the i2c port. Perform load detection on the DAC (if + * present) to see if the display is connected via VGA. Sets the cached status + * of both outputs. The status is marked dirty again in the BlockHandler. + */ +void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c) +{ + xf86MonPtr monInfo = ProbeDDC(i2c); + xf86OutputPtr connected = NULL; + Bool load = dac && G80DacLoadDetect(dac); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + if(load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = dac; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + if(monInfo && !load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = sor; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(connected) + xf86OutputSetEDID(connected, monInfo); +} + +/* + * Reset the cached output status for all outputs. Called from G80BlockHandler. + */ +void +G80OutputResetCachedStatus(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + for(i = 0; i < xf86_config->num_output; i++) { + G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private; + pPriv->cached_status = XF86OutputStatusUnknown; + } +} + +DisplayModePtr +G80OutputGetDDCModes(xf86OutputPtr output) +{ + /* The EDID is read as part of the detect step */ + output->funcs->detect(output); + return xf86OutputGetEDIDModes(output); +} + +void +G80OutputDestroy(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + if(pPriv->partner) + ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL; + else + xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); + pPriv->i2c = NULL; +} + +Bool +G80CreateOutputs(ScrnInfoPtr pScrn) +{ + G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) + return FALSE; + + /* For each DDC port, create an output for the attached ORs */ + for(i = 0; i < 4; i++) { + xf86OutputPtr dac = NULL, sor = NULL; + I2CBusPtr i2c; + char i2cName[16]; + + if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) + /* No outputs on this port */ + continue; + + snprintf(i2cName, sizeof(i2cName), "I2C%i", i); + i2c = G80I2CInit(pScrn, i2cName, i); + if(!i2c) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize I2C for port %i.\n", + i); + continue; + } + + if(pNv->i2cMap[i].dac != -1) + dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac); + if(pNv->i2cMap[i].sor != -1) + sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + pPriv->partner = sor; + pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_OFF; + } + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + pPriv->partner = dac; + pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_ASPECT; + } + } + + if(pNv->lvds.present) { + xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS); + G80OutputPrivPtr pPriv = lvds->driver_private; + + pPriv->scale = G80_SCALE_ASPECT; + } + + /* For each output, set the crtc and clone masks */ + for(i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + /* Any output can connect to any head */ + output->possible_crtcs = 0x3; + output->possible_clones = 0; + } + + return TRUE; +} diff --git a/driver/xf86-video-nv/src/g80_output.h b/driver/xf86-video-nv/src/g80_output.h new file mode 100644 index 000000000..33514c61f --- /dev/null +++ b/driver/xf86-video-nv/src/g80_output.h @@ -0,0 +1,31 @@ +typedef struct G80OutputPrivRec { + ORType type; + ORNum or; + PanelType panelType; + DisplayModePtr nativeMode; + enum G80ScaleMode scale; + + xf86OutputPtr partner; + I2CBusPtr i2c; + + xf86OutputStatus cached_status; + + void (*set_pclk)(xf86OutputPtr, int pclk); +} G80OutputPrivRec, *G80OutputPrivPtr; + +void G80OutputSetPClk(xf86OutputPtr, int pclk); +int G80OutputModeValid(xf86OutputPtr, DisplayModePtr); +void G80OutputPrepare(xf86OutputPtr); +void G80OutputCommit(xf86OutputPtr); +void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c); +void G80OutputResetCachedStatus(ScrnInfoPtr); +DisplayModePtr G80OutputGetDDCModes(xf86OutputPtr); +void G80OutputDestroy(xf86OutputPtr); +Bool G80CreateOutputs(ScrnInfoPtr); + +/* g80_dac.c */ +xf86OutputPtr G80CreateDac(ScrnInfoPtr, ORNum); +Bool G80DacLoadDetect(xf86OutputPtr); + +/* g80_sor.c */ +xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum, PanelType); diff --git a/driver/xf86-video-nv/src/g80_sor.c b/driver/xf86-video-nv/src/g80_sor.c new file mode 100644 index 000000000..c98b66d42 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_sor.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#include <X11/Xatom.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static void +G80SorSetPClk(xf86OutputPtr output, int pclk) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int orOff = 0x800 * pPriv->or; + const int limit = 165000; + + pNv->reg[(0x00614300+orOff)/4] = (pclk > limit) ? 0x101 : 0; +} + +static void +G80SorDPMSSet(xf86OutputPtr output, int mode) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int off = 0x800 * pPriv->or; + CARD32 tmp; + + while(pNv->reg[(0x0061C004+off)/4] & 0x80000000); + + tmp = pNv->reg[(0x0061C004+off)/4]; + tmp |= 0x80000000; + + if(mode == DPMSModeOn) + tmp |= 1; + else + tmp &= ~1; + + pNv->reg[(0x0061C004+off)/4] = tmp; + while((pNv->reg[(0x61C030+off)/4] & 0x10000000)); +} + +static int +G80TMDSModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + // Disable dual-link modes until I can find a way to make them work + // reliably. + if (mode->Clock > 165000) + return MODE_CLOCK_HIGH; + + return G80OutputModeValid(output, mode); +} + +static int +G80LVDSModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr native = pPriv->nativeMode; + + // Ignore modes larger than the native res. + if (mode->HDisplay > native->HDisplay || mode->VDisplay > native->VDisplay) + return MODE_PANEL; + + return G80OutputModeValid(output, mode); +} + +static void +G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + G80OutputPrivPtr pPriv = output->driver_private; + const int sorOff = 0x40 * pPriv->or; + CARD32 type; + + if(!adjusted_mode) { + /* Disconnect the SOR */ + C(0x00000600 + sorOff, 0); + return; + } + + if(pPriv->panelType == LVDS) + type = 0; + else if(adjusted_mode->Clock > 165000) + type = 0x500; + else + type = 0x100; + + // This wouldn't be necessary, but the server is stupid and calls + // G80SorDPMSSet after the output is disconnected, even though the hardware + // turns it off automatically. + G80SorDPMSSet(output, DPMSModeOn); + + C(0x00000600 + sorOff, + (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | + type | + ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) | + ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0)); + + G80CrtcSetScale(output->crtc, adjusted_mode, pPriv->scale); +} + +static xf86OutputStatus +G80SorDetect(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; + + G80OutputPartnersDetect(pPriv->partner, output, pPriv->i2c); + return pPriv->cached_status; +} + +static xf86OutputStatus +G80SorLVDSDetect(xf86OutputPtr output) +{ + /* Assume LVDS is always connected */ + return XF86OutputStatusConnected; +} + +static void +G80SorDestroy(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + G80OutputDestroy(output); + + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); + + xfree(output->driver_private); + output->driver_private = NULL; +} + +static void G80SorSetModeBackend(DisplayModePtr dst, const DisplayModePtr src) +{ + // Stash the backend mode timings from src into dst + dst->Clock = src->Clock; + dst->Flags = src->Flags; + dst->CrtcHDisplay = src->CrtcHDisplay; + dst->CrtcHBlankStart = src->CrtcHBlankStart; + dst->CrtcHSyncStart = src->CrtcHSyncStart; + dst->CrtcHSyncEnd = src->CrtcHSyncEnd; + dst->CrtcHBlankEnd = src->CrtcHBlankEnd; + dst->CrtcHTotal = src->CrtcHTotal; + dst->CrtcHSkew = src->CrtcHSkew; + dst->CrtcVDisplay = src->CrtcVDisplay; + dst->CrtcVBlankStart = src->CrtcVBlankStart; + dst->CrtcVSyncStart = src->CrtcVSyncStart; + dst->CrtcVSyncEnd = src->CrtcVSyncEnd; + dst->CrtcVBlankEnd = src->CrtcVBlankEnd; + dst->CrtcVTotal = src->CrtcVTotal; + dst->CrtcHAdjusted = src->CrtcHAdjusted; + dst->CrtcVAdjusted = src->CrtcVAdjusted; +} + +static Bool +G80SorModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr native = pPriv->nativeMode; + + if(native && pPriv->scale != G80_SCALE_OFF) { + G80SorSetModeBackend(adjusted_mode, native); + // This mode is already "fixed" + G80CrtcSkipModeFixup(output->crtc); + } + + return TRUE; +} + +static Bool +G80SorTMDSModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + int scrnIndex = output->scrn->scrnIndex; + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr modes = output->probed_modes; + + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); + + if(modes) { + // Find the preferred mode and use that as the "native" mode. + // If no preferred mode is available, use the first one. + DisplayModePtr mode; + + // Find the preferred mode. + for(mode = modes; mode; mode = mode->next) { + if(mode->type & M_T_PREFERRED) { + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: preferred mode is %s\n", + output->name, mode->name); + break; + } + } + + // XXX: May not want to allow scaling if no preferred mode is found. + if(!mode) { + mode = modes; + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: no preferred mode found, using %s\n", + output->name, mode->name); + } + + pPriv->nativeMode = xf86DuplicateMode(mode); + G80CrtcDoModeFixup(pPriv->nativeMode, mode); + } + + return G80SorModeFixup(output, mode, adjusted_mode); +} + +static DisplayModePtr +G80SorGetLVDSModes(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + return xf86DuplicateMode(pPriv->nativeMode); +} + +#ifdef RANDR_12_INTERFACE +#define MAKE_ATOM(a) MakeAtom((a), sizeof(a) - 1, TRUE); + +struct property { + Atom atom; + INT32 range[2]; +}; + +static struct { + struct property dither; + struct property scale; +} properties; + +static void +G80SorCreateResources(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + G80Ptr pNv = G80PTR(pScrn); + int data, err; + const char *s; + + /******** dithering ********/ + properties.dither.atom = MAKE_ATOM("dither"); + properties.dither.range[0] = 0; + properties.dither.range[1] = 1; + err = RRConfigureOutputProperty(output->randr_output, + properties.dither.atom, FALSE, TRUE, FALSE, + 2, properties.dither.range); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to configure dithering property for %s: error %d\n", + output->name, err); + + // Set the default value + data = pNv->Dither; + err = RRChangeOutputProperty(output->randr_output, properties.dither.atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, FALSE); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to set dithering property for %s: error %d\n", + output->name, err); + + /******** scaling ********/ + properties.scale.atom = MAKE_ATOM("scale"); + err = RRConfigureOutputProperty(output->randr_output, + properties.scale.atom, FALSE, FALSE, + FALSE, 0, NULL); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to configure scaling property for %s: error %d\n", + output->name, err); + + // Set the default value + s = "aspect"; + err = RRChangeOutputProperty(output->randr_output, properties.scale.atom, + XA_STRING, 8, PropModeReplace, strlen(s), + (pointer)s, FALSE, FALSE); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to set scaling property for %s: error %d\n", + output->name, err); +} + +static Bool +G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + if(prop == properties.dither.atom) { + INT32 i; + + if(val->type != XA_INTEGER || val->format != 32 || val->size != 1) + return FALSE; + + i = *(INT32*)val->data; + if(i < properties.dither.range[0] || i > properties.dither.range[1]) + return FALSE; + + G80CrtcSetDither(output->crtc, i, TRUE); + return TRUE; + } else if(prop == properties.scale.atom) { + const char *s; + enum G80ScaleMode oldScale, scale; + int i; + const struct { + const char *name; + enum G80ScaleMode scale; + } modes[] = { + { "off", G80_SCALE_OFF }, + { "aspect", G80_SCALE_ASPECT }, + { "fill", G80_SCALE_FILL }, + { "center", G80_SCALE_CENTER }, + { NULL, 0 }, + }; + + if(val->type != XA_STRING || val->format != 8) + return FALSE; + s = (char*)val->data; + + for(i = 0; modes[i].name; i++) { + const char *name = modes[i].name; + const int len = strlen(name); + + if(val->size == len && !strncmp(name, s, len)) { + scale = modes[i].scale; + break; + } + } + if(!modes[i].name) + return FALSE; + if(scale == G80_SCALE_OFF && pPriv->panelType == LVDS) + // LVDS requires scaling + return FALSE; + + oldScale = pPriv->scale; + pPriv->scale = scale; + if(output->crtc) { + xf86CrtcPtr crtc = output->crtc; + + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to set scaling to %s for output %s\n", + modes[i].name, output->name); + + // Restore old scale and try again. + pPriv->scale = oldScale; + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, + crtc->desiredRotation, crtc->desiredX, + crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to restore old scaling for output %s\n", + output->name); + } + + return FALSE; + } + } + return TRUE; + } + + return FALSE; +} +#endif // RANDR_12_INTERFACE + +static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = { + .dpms = G80SorDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80TMDSModeValid, + .mode_fixup = G80SorTMDSModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80SorModeSet, + .detect = G80SorDetect, + .get_modes = G80OutputGetDDCModes, +#ifdef RANDR_12_INTERFACE + .create_resources = G80SorCreateResources, + .set_property = G80SorSetProperty, +#endif + .destroy = G80SorDestroy, +}; + +static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = { + .dpms = G80SorDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80LVDSModeValid, + .mode_fixup = G80SorModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80SorModeSet, + .detect = G80SorLVDSDetect, + .get_modes = G80SorGetLVDSModes, +#ifdef RANDR_12_INTERFACE + .create_resources = G80SorCreateResources, + .set_property = G80SorSetProperty, +#endif + .destroy = G80SorDestroy, +}; + +static DisplayModePtr +GetLVDSNativeMode(G80Ptr pNv) +{ + DisplayModePtr mode = xnfcalloc(1, sizeof(DisplayModeRec)); + const CARD32 size = pNv->reg[0x00610B4C/4]; + const int width = size & 0x3fff; + const int height = (size >> 16) & 0x3fff; + + mode->HDisplay = mode->CrtcHDisplay = width; + mode->VDisplay = mode->CrtcVDisplay = height; + mode->Clock = pNv->reg[0x610AD4/4] & 0x3fffff; + mode->CrtcHBlankStart = pNv->reg[0x610AFC/4]; + mode->CrtcHSyncEnd = pNv->reg[0x610B04/4]; + mode->CrtcHBlankEnd = pNv->reg[0x610AE8/4]; + mode->CrtcHTotal = pNv->reg[0x610AF4/4]; + + mode->next = mode->prev = NULL; + mode->status = MODE_OK; + mode->type = M_T_DRIVER | M_T_PREFERRED; + + xf86SetModeDefaultName(mode); + + return mode; +} + +xf86OutputPtr +G80CreateSor(ScrnInfoPtr pScrn, ORNum or, PanelType panelType) +{ + G80Ptr pNv = G80PTR(pScrn); + G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1); + const int off = 0x800 * or; + xf86OutputPtr output; + char orName[5]; + const xf86OutputFuncsRec *funcs; + + if(!pPriv) + return FALSE; + + if(panelType == LVDS) { + strcpy(orName, "LVDS"); + funcs = &G80SorLVDSOutputFuncs; + } else { + snprintf(orName, 5, "DVI%d", or); + pNv->reg[(0x61C00C+off)/4] = 0x03010700; + pNv->reg[(0x61C010+off)/4] = 0x0000152f; + pNv->reg[(0x61C014+off)/4] = 0x00000000; + pNv->reg[(0x61C018+off)/4] = 0x00245af8; + funcs = &G80SorTMDSOutputFuncs; + } + + output = xf86OutputCreate(pScrn, funcs, orName); + + pPriv->type = SOR; + pPriv->or = or; + pPriv->panelType = panelType; + pPriv->cached_status = XF86OutputStatusUnknown; + if(panelType == TMDS) + pPriv->set_pclk = G80SorSetPClk; + output->driver_private = pPriv; + output->interlaceAllowed = TRUE; + output->doubleScanAllowed = TRUE; + + if(panelType == LVDS) { + pPriv->nativeMode = GetLVDSNativeMode(pNv); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s native size %dx%d\n", + orName, pPriv->nativeMode->HDisplay, + pPriv->nativeMode->VDisplay); + } + + return output; +} diff --git a/driver/xf86-video-nv/src/g80_xaa.h b/driver/xf86-video-nv/src/g80_xaa.h index e2f1f63c5..6c1d7652f 100644 --- a/driver/xf86-video-nv/src/g80_xaa.h +++ b/driver/xf86-video-nv/src/g80_xaa.h @@ -1 +1,6 @@ +void G80Sync(ScrnInfoPtr pScrn); +void G80DMAKickoffCallback(ScrnInfoPtr pScrn); +void G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1); +void G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask); +void G80SetClip(G80Ptr pNv, int x, int y, int w, int h); Bool G80XAAInit(ScreenPtr); diff --git a/driver/xf86-video-nv/src/local_xf86Rename.h b/driver/xf86-video-nv/src/local_xf86Rename.h new file mode 100644 index 000000000..f3a07c6b4 --- /dev/null +++ b/driver/xf86-video-nv/src/local_xf86Rename.h @@ -0,0 +1,23 @@ +/* + *Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define XF86NAME(x) nv_##x diff --git a/driver/xf86-video-nv/src/riva_const.h b/driver/xf86-video-nv/src/riva_const.h index 4949fc124..890bcaaa6 100644 --- a/driver/xf86-video-nv/src/riva_const.h +++ b/driver/xf86-video-nv/src/riva_const.h @@ -1,5 +1,3 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_const.h $ */ - #ifndef __RIVA_CONST_H__ #define __RIVA_CONST_H__ @@ -8,4 +6,3 @@ #define RIVA_DRIVER_NAME "riva128" #endif /* __RIVA_CONST_H__ */ - |