[PATCH r128] Port to RandR

Alex Deucher alexdeucher at gmail.com
Tue Jul 1 09:56:07 PDT 2014


On Sun, Jun 1, 2014 at 4:03 PM, Connor Behan <connor.behan at gmail.com> wrote:
> This rearranges the r128 code to use the Crtc and Ouput interfaces which
> should make the driver easier to maintain in the long run. User visible
> changes include DDC detection working in more cases and the ability to
> have multiple monitors with DRI.
>
> Some choices have been made to conserve memory. Modes can be switched up
> to the highest resolution specified in xorg.conf. If this is 1024x768
> for example, the front buffer will be 1024x768 instead of 1024x1024.
> This means 90 and 270 degree rotations will not work. However, scalings,
> reflections and 180 degree rotations can be set with the xrandr client
> program.
>
> Signed-off-by: Connor Behan <connor.behan at gmail.com>

A few comments below, but they can be addressed later if you want.
Other than that the patch is:

Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  configure.ac      |    2 +-
>  src/Makefile.am   |    3 +-
>  src/r128.h        |   48 +-
>  src/r128_crtc.c   |  476 ++++++++++++++++++++
>  src/r128_cursor.c |  294 ++++++------
>  src/r128_driver.c | 1287 +++++++++++------------------------------------------
>  src/r128_output.c |  465 +++++++++++++++++++
>  src/r128_probe.c  |    1 -
>  src/r128_probe.h  |   79 ++++
>  src/r128_video.c  |   17 +-
>  10 files changed, 1479 insertions(+), 1193 deletions(-)
>  create mode 100644 src/r128_crtc.c
>  create mode 100644 src/r128_output.c
>
> diff --git a/configure.ac b/configure.ac
> index 56554ec..3cc3113 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -76,7 +76,7 @@ XORG_DRIVER_CHECK_EXT(XF86MISC, xf86miscproto)
>  XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
>
>  # Obtain compiler/linker options for the driver dependencies
> -PKG_CHECK_MODULES(XORG, [xorg-server >= 1.2 xproto fontsproto $REQUIRED_MODULES])
> +PKG_CHECK_MODULES(XORG, [xorg-server >= 1.3 xproto fontsproto $REQUIRED_MODULES])
>  PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1],
>                    HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]),
>                    HAVE_XEXTPROTO_71="no")
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 23e6c49..e4618ea 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -41,7 +41,8 @@ r128_drv_la_LDFLAGS = -module -avoid-version
>  r128_drv_ladir = @moduledir@/drivers
>  r128_drv_la_SOURCES = \
>         r128_accel.c r128_cursor.c r128_dga.c r128_driver.c \
> -       r128_video.c r128_misc.c r128_probe.c $(R128_EXA_SRCS) $(R128_DRI_SRCS)
> +       r128_video.c r128_misc.c r128_crtc.c r128_output.c r128_probe.c \
> +       $(R128_EXA_SRCS) $(R128_DRI_SRCS)
>
>  EXTRA_DIST = \
>          compat-api.h \
> diff --git a/src/r128.h b/src/r128.h
> index ee0b1d4..fe757f8 100644
> --- a/src/r128.h
> +++ b/src/r128.h
> @@ -74,6 +74,7 @@
>  #endif
>
>  #include "fb.h"
> +#include "xf86Crtc.h"
>
>  #include "compat-api.h"
>  #include "atipcirename.h"
> @@ -260,16 +261,6 @@ typedef struct {
>      DisplayModePtr     mode;
>  } R128FBLayout;
>
> -typedef enum
> -{
> -    MT_NONE,
> -    MT_CRT,
> -    MT_LCD,
> -    MT_DFP,
> -    MT_CTV,
> -    MT_STV
> -} R128MonitorType;
> -
>  #ifdef USE_EXA
>  struct r128_2d_state {
>      Bool in_use;
> @@ -523,10 +514,10 @@ typedef struct {
>
>      Bool              isDFP;
>      Bool              isPro2;
> -    I2CBusPtr         pI2CBus;
> -    CARD32            DDCReg;
> +    Bool              DDC;
>
>      Bool              VGAAccess;
> +    R128BIOSConnector BiosConnector[R128_MAX_BIOS_CONNECTOR];
>
>      /****** Added for dualhead support *******************/
>      BOOL              HasCRTC2;     /* M3/M4 */
> @@ -562,6 +553,39 @@ extern int         R128MinBits(int val);
>
>  extern void        R128InitVideo(ScreenPtr pScreen);
>
> +extern void        R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info);
> +extern void        R128InitFPRegisters(R128SavePtr orig, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
> +extern Bool        R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y);
> +extern Bool        R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
> +extern void        R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, double dot_clock);
> +extern Bool        R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, R128InfoPtr info, DisplayModePtr mode);
> +extern Bool        R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y);
> +extern Bool        R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info);
> +extern void        R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, double dot_clock);
> +extern Bool        R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, R128InfoPtr info, DisplayModePtr mode);
> +extern void        R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestoreCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
> +extern void        R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore);
> +
> +extern void        r128_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg);
> +extern void        r128_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y);
> +extern void        r128_crtc_show_cursor(xf86CrtcPtr crtc);
> +extern void        r128_crtc_hide_cursor(xf86CrtcPtr crtc);
> +extern void        r128_crtc_load_cursor_image(xf86CrtcPtr crtc, unsigned char *src);
> +
> +extern Bool        R128SetupConnectors(ScrnInfoPtr pScrn);
> +extern Bool        R128AllocateControllers(ScrnInfoPtr pScrn, int mask);
> +extern void        R128Blank(ScrnInfoPtr pScrn);
> +extern void        R128Unblank(ScrnInfoPtr pScrn);
> +extern void        R128DPMSSetOn(xf86OutputPtr output);
> +extern void        R128DPMSSetOff(xf86OutputPtr output);
> +extern DisplayModePtr R128ProbeOutputModes(xf86OutputPtr output);
> +
>  #ifdef R128DRI
>  extern Bool        R128DRIScreenInit(ScreenPtr pScreen);
>  extern void        R128DRICloseScreen(ScreenPtr pScreen);
> diff --git a/src/r128_crtc.c b/src/r128_crtc.c
> new file mode 100644
> index 0000000..35e1fee
> --- /dev/null
> +++ b/src/r128_crtc.c
> @@ -0,0 +1,476 @@
> +/*
> + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
> + *                VA Linux Systems Inc., Fremont, California.
> + *
> + * All Rights Reserved.
> + *
> + * 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 on 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
> + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
> + * THEIR SUPPLIERS 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 <string.h>
> +#include <stdio.h>
> +
> +#include "xf86.h"
> +#include "xf86Modes.h"
> +
> +#include "r128.h"
> +#include "r128_probe.h"
> +#include "r128_reg.h"
> +
> +static void r128_crtc_load_lut(xf86CrtcPtr crtc);
> +
> +static void r128_crtc_dpms(xf86CrtcPtr crtc, int mode)
> +{
> +    int mask;
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +
> +    /* XXX: The HSYNC and VSYNC bits for CRTC2 don't exist on the r128? */
> +    mask = r128_crtc->crtc_id ? R128_CRTC2_DISP_DIS : (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_VSYNC_DIS);
> +

You might also want to disable the CRTC altogether in the
non-DPMSModeOn cases using CRTC_GEN_CNTL.CRTC_EN and
CRTC2_GEN_CNTL.CRTC2_EN.  It should save some additional power.

> +    switch (mode) {
> +    case DPMSModeOn:
> +        if (r128_crtc->crtc_id) {
> +            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask);
> +        } else {
> +            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
> +        }
> +        break;
> +    case DPMSModeStandby:
> +        if (r128_crtc->crtc_id) {
> +            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
> +        } else {
> +            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS), ~mask);
> +        }
> +        break;
> +    case DPMSModeSuspend:
> +        if (r128_crtc->crtc_id) {
> +            OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask);
> +        } else {
> +            OUTREGP(R128_CRTC_EXT_CNTL, (R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS), ~mask);
> +        }
> +        break;
> +    case DPMSModeOff:
> +        if (r128_crtc->crtc_id) {
> +            OUTREGP(R128_CRTC2_GEN_CNTL, mask, ~mask);
> +        } else {
> +            OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
> +        }
> +        break;
> +    }
> +
> +    if (mode != DPMSModeOff)
> +        r128_crtc_load_lut(crtc);
> +}
> +
> +void r128_crtc_load_lut(xf86CrtcPtr crtc)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    int i;
> +
> +    if (!crtc->enabled)
> +        return;
> +
> +    PAL_SELECT(r128_crtc->crtc_id);
> +
> +    for (i = 0; i < 256; i++) {
> +        OUTPAL(i, r128_crtc->lut_r[i], r128_crtc->lut_g[i], r128_crtc->lut_b[i]);
> +    }
> +}
> +
> +static Bool r128_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode)
> +{
> +    return TRUE;
> +}
> +
> +static void r128_crtc_mode_prepare(xf86CrtcPtr crtc)
> +{
> +    r128_crtc_dpms(crtc, DPMSModeOff);
> +}
> +
> +static void r128_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    R128OutputType otype = OUTPUT_NONE;
> +
> +    double dot_clock = adjusted_mode->Clock / 1000.0;
> +    int i;
> +
> +    if (r128_crtc->cursor_offset) r128_crtc_hide_cursor(crtc);
> +    xf86PrintModeline(pScrn->scrnIndex, adjusted_mode);
> +    R128InitCommonRegisters(&info->ModeReg, info);
> +
> +    for (i = 0; i < xf86_config->num_output; i++) {
> +        xf86OutputPtr output = xf86_config->output[i];
> +        R128OutputPrivatePtr r128_output = output->driver_private;
> +
> +        if (output->crtc == crtc)
> +            otype = r128_output->type;
> +    }
> +
> +    switch (r128_crtc->crtc_id) {
> +    case 0:
> +        R128InitCrtcRegisters(pScrn, &info->ModeReg, adjusted_mode, info);
> +       R128InitCrtcBase(crtc, &info->ModeReg, x, y);
> +        if (dot_clock) {
> +            R128InitPLLRegisters(pScrn, &info->ModeReg, &info->pll, dot_clock);
> +            R128InitDDARegisters(pScrn, &info->ModeReg, &info->pll, info, adjusted_mode);
> +        } else {
> +            info->ModeReg.ppll_ref_div         = info->SavedReg.ppll_ref_div;
> +            info->ModeReg.ppll_div_3           = info->SavedReg.ppll_div_3;
> +            info->ModeReg.htotal_cntl          = info->SavedReg.htotal_cntl;
> +            info->ModeReg.dda_config           = info->SavedReg.dda_config;
> +            info->ModeReg.dda_on_off           = info->SavedReg.dda_on_off;
> +        }
> +        break;
> +    case 1:
> +        R128InitCrtc2Registers(pScrn, &info->ModeReg, adjusted_mode, info);
> +       R128InitCrtc2Base(crtc, &info->ModeReg, x, y);
> +        if (dot_clock) {
> +            R128InitPLL2Registers(pScrn, &info->ModeReg, &info->pll, dot_clock);
> +            R128InitDDA2Registers(pScrn, &info->ModeReg, &info->pll, info, adjusted_mode);
> +        }
> +        break;
> +    }
> +
> +    if (otype == OUTPUT_DVI || otype == OUTPUT_LVDS)
> +        R128InitFPRegisters(&info->SavedReg, &info->ModeReg, adjusted_mode, info);

You might want to split R128InitFPRegisters() up into specific
functions for TMDS and LVDS.  I'm not sure if it properly handles the
combination of LVDS + TMDS correctly.

> +    R128RestoreCommonRegisters(pScrn, &info->ModeReg);
> +
> +    switch (r128_crtc->crtc_id) {
> +    case 0:
> +        R128RestoreDDARegisters(pScrn, &info->ModeReg);
> +        R128RestoreCrtcRegisters(pScrn, &info->ModeReg);
> +        R128RestorePLLRegisters(pScrn, &info->ModeReg);
> +        break;
> +    case 1:
> +        R128RestoreDDA2Registers(pScrn, &info->ModeReg);
> +        R128RestoreCrtc2Registers(pScrn, &info->ModeReg);
> +        R128RestorePLL2Registers(pScrn, &info->ModeReg);
> +       break;
> +    }
> +
> +    if (otype == OUTPUT_DVI || otype == OUTPUT_LVDS)
> +        R128RestoreFPRegisters(pScrn, &info->ModeReg);
> +

Same here.  You may want to split this up between TMDS and LVDS.

> +    /* XXX: InitFPRegisters looks similar to radeon's InitRMXRegisters so
> +     * maybe it should be called from mode_set in the output code.
> +     */

You could probably break out the RMX controls as well since you can
use the RMX scaler on either TMDS or LVDS.

> +    if (r128_crtc->cursor_offset) r128_crtc_show_cursor(crtc);

Is this needed?

> +}
> +
> +static void r128_crtc_mode_commit(xf86CrtcPtr crtc)
> +{
> +    r128_crtc_dpms(crtc, DPMSModeOn);
> +}
> +
> +static void r128_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size)
> +{
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    int i;
> +
> +    for (i = 0; i < 256; i++) {
> +        r128_crtc->lut_r[i] = red[i] >> 8;
> +        r128_crtc->lut_g[i] = green[i] >> 8;
> +        r128_crtc->lut_b[i] = blue[i] >> 8;
> +    }
> +
> +    r128_crtc_load_lut(crtc);
> +}
> +
> +static Bool r128_crtc_lock(xf86CrtcPtr crtc)
> +{
> +    ScrnInfoPtr   pScrn   = crtc->scrn;
> +    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
> +    R128InfoPtr   info    = R128PTR(pScrn);
> +
> +#ifdef HAVE_XAA_H
> +    if (info->accel) info->accel->Sync(pScrn);
> +#endif
> +#ifdef USE_EXA
> +    if (info->ExaDriver) exaWaitSync(pScreen);
> +#endif
> +
> +    return FALSE;
> +}
> +
> +static void r128_crtc_unlock(xf86CrtcPtr crtc)
> +{
> +    ScrnInfoPtr   pScrn   = crtc->scrn;
> +    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
> +    R128InfoPtr   info    = R128PTR(pScrn);
> +
> +#ifdef HAVE_XAA_H
> +    if (info->accel) info->accel->Sync(pScrn);
> +#endif
> +#ifdef USE_EXA
> +    if (info->ExaDriver) exaWaitSync(pScreen);
> +#endif
> +}
> +
> +#ifdef HAVE_XAA_H
> +static FBLinearPtr r128_xf86AllocateOffscreenLinear(ScreenPtr pScreen, int length, int granularity,
> +                                                MoveLinearCallbackProcPtr moveCB,
> +                                                RemoveLinearCallbackProcPtr removeCB,
> +                                                pointer privData)
> +{
> +    FBLinearPtr linear;
> +    int max_size;
> +
> +    linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, removeCB, privData);
> +    if (linear != NULL) return linear;
> +
> +    /* The above allocation did not succeed, so purge unlocked stuff and try again. */
> +    xf86QueryLargestOffscreenLinear(pScreen, &max_size, granularity, PRIORITY_EXTREME);
> +
> +    if (max_size < length) return NULL;
> +    xf86PurgeUnlockedOffscreenAreas(pScreen);
> +
> +    linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, removeCB, privData);
> +    return linear;
> +}
> +#endif
> +
> +static void *r128_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
> +{
> +    ScrnInfoPtr   pScrn   = crtc->scrn;
> +    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
> +    R128InfoPtr   info    = R128PTR(pScrn);
> +
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    unsigned long rotate_offset = 0;
> +    unsigned long rotate_pitch;
> +    int cpp = pScrn->bitsPerPixel / 8;
> +    int align = 4096;
> +    int size;
> +
> +    rotate_pitch = pScrn->displayWidth * cpp;
> +    size = rotate_pitch * height;
> +
> +#ifdef USE_EXA
> +    if (info->ExaDriver) {
> +        assert(r128_crtc->rotate_mem_exa == NULL);
> +        r128_crtc->rotate_mem_exa = exaOffscreenAlloc(pScreen, size, align, TRUE, NULL, NULL);
> +
> +        if (r128_crtc->rotate_mem_exa == NULL) {
> +           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> +                      "Couldn't allocate shadow memory for rotated CRTC\n");
> +           return NULL;
> +       }
> +
> +        rotate_offset = r128_crtc->rotate_mem_exa->offset;
> +    }
> +#endif
> +#ifdef HAVE_XAA_H
> +    if (info->accel) {
> +        size = (size + cpp - 1) / cpp;
> +        align = (align + cpp - 1) / cpp;
> +
> +        assert(r128_crtc->rotate_mem_xaa == NULL);
> +        r128_crtc->rotate_mem_xaa = r128_xf86AllocateOffscreenLinear(pScreen, size, align, NULL, NULL, NULL);
> +
> +        if (r128_crtc->rotate_mem_exa == NULL) {
> +           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> +                      "Couldn't allocate shadow memory for rotated CRTC\n");
> +           return NULL;
> +       }
> +
> +        rotate_offset = r128_crtc->rotate_mem_xaa->offset * cpp;
> +    }
> +#endif
> +
> +    /* If allocations failed or if there was no accel. */
> +    if (rotate_offset == 0)
> +        return NULL;
> +
> +    return info->FB + rotate_offset;
> +}
> +
> +static PixmapPtr r128_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    PixmapPtr rotate_pixmap;
> +    unsigned long rotate_pitch;
> +    int cpp = pScrn->bitsPerPixel / 8;
> +
> +    if (!data) data = r128_crtc_shadow_allocate(crtc, width, height);
> +
> +    rotate_pitch = pScrn->displayWidth * cpp;
> +    rotate_pixmap = GetScratchPixmapHeader(xf86ScrnToScreen(pScrn),
> +                                           width, height,
> +                                           pScrn->depth,
> +                                           pScrn->bitsPerPixel,
> +                                           rotate_pitch,
> +                                           data);
> +
> +    if (rotate_pixmap == NULL) {
> +        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> +                   "Couldn't allocate shadow memory for rotated CRTC\n");
> +        return NULL;
> +    }
> +
> +    return rotate_pixmap;
> +}
> +
> +static void r128_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
> +{
> +    ScrnInfoPtr   pScrn   = crtc->scrn;
> +    ScreenPtr     pScreen = xf86ScrnToScreen(pScrn);
> +    R128InfoPtr   info    = R128PTR(pScrn);
> +
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +
> +    if (rotate_pixmap) FreeScratchPixmapHeader(rotate_pixmap);
> +
> +    if (data) {
> +#ifdef USE_EXA
> +        if (info->ExaDriver && r128_crtc->rotate_mem_exa != NULL) {
> +            exaOffscreenFree(pScreen, r128_crtc->rotate_mem_exa);
> +           r128_crtc->rotate_mem_exa = NULL;
> +        }
> +#endif
> +#ifdef HAVE_XAA_H
> +        if (info->accel) {
> +            xf86FreeOffscreenLinear(r128_crtc->rotate_mem_xaa);
> +            r128_crtc->rotate_mem_xaa = NULL;
> +        }
> +#endif
> +    }
> +}
> +
> +static const xf86CrtcFuncsRec r128_crtc_funcs = {
> +    .dpms = r128_crtc_dpms,
> +    .save = NULL,
> +    .restore = NULL,
> +    .mode_fixup = r128_crtc_mode_fixup,
> +    .prepare = r128_crtc_mode_prepare,
> +    .mode_set = r128_crtc_mode_set,
> +    .commit = r128_crtc_mode_commit,
> +    .gamma_set = r128_crtc_gamma_set,
> +    .lock = r128_crtc_lock,
> +    .unlock = r128_crtc_unlock,
> +    .shadow_create = r128_crtc_shadow_create,
> +    .shadow_allocate = r128_crtc_shadow_allocate,
> +    .shadow_destroy = r128_crtc_shadow_destroy,
> +    .set_cursor_colors = r128_crtc_set_cursor_colors,
> +    .set_cursor_position = r128_crtc_set_cursor_position,
> +    .show_cursor = r128_crtc_show_cursor,
> +    .hide_cursor = r128_crtc_hide_cursor,
> +    .load_cursor_image = r128_crtc_load_cursor_image,
> +    .destroy = NULL,
> +};
> +
> +Bool R128AllocateControllers(ScrnInfoPtr pScrn, int mask)
> +{
> +    R128EntPtr pR128Ent = R128EntPriv(pScrn);
> +    R128InfoPtr info = R128PTR(pScrn);
> +
> +    if (mask & 1) {
> +        if (pR128Ent->Controller[0])
> +            return TRUE;
> +
> +        pR128Ent->pCrtc[0] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
> +        if (!pR128Ent->pCrtc[0])
> +            return FALSE;
> +
> +        pR128Ent->Controller[0] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
> +        if (!pR128Ent->Controller[0])
> +            return FALSE;
> +
> +        pR128Ent->pCrtc[0]->driver_private = pR128Ent->Controller[0];
> +        pR128Ent->Controller[0]->crtc_id = 0;
> +    }
> +
> +    if (mask & 2) {
> +        if (!info->HasCRTC2)
> +            return TRUE;
> +
> +        pR128Ent->pCrtc[1] = xf86CrtcCreate(pScrn, &r128_crtc_funcs);
> +        if (!pR128Ent->pCrtc[1])
> +            return FALSE;
> +
> +        pR128Ent->Controller[1] = xnfcalloc(sizeof(R128CrtcPrivateRec), 1);
> +        if (!pR128Ent->Controller[1]) {
> +            free(pR128Ent->Controller[0]);
> +            return FALSE;
> +        }
> +
> +        pR128Ent->pCrtc[1]->driver_private = pR128Ent->Controller[1];
> +        pR128Ent->Controller[1]->crtc_id = 1;
> +    }
> +
> +    return TRUE;
> +}
> +
> +void R128Blank(ScrnInfoPtr pScrn)
> +{
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    xf86OutputPtr output;
> +    xf86CrtcPtr crtc;
> +    int o, c;
> +
> +    for (c = 0; c < xf86_config->num_crtc; c++) {
> +        crtc = xf86_config->crtc[c];
> +        for (o = 0; o < xf86_config->num_output; o++) {
> +            output = xf86_config->output[o];
> +            if (output->crtc != crtc)
> +                continue;
> +
> +            output->funcs->dpms(output, DPMSModeOff);
> +        }
> +        crtc->funcs->dpms(crtc, DPMSModeOff);
> +    }
> +}
> +
> +void R128Unblank(ScrnInfoPtr pScrn)
> +{
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    xf86OutputPtr output;
> +    xf86CrtcPtr crtc;
> +    int o, c;
> +
> +    for (c = 0; c < xf86_config->num_crtc; c++) {
> +        crtc = xf86_config->crtc[c];
> +        if (!crtc->enabled)
> +            continue;
> +        crtc->funcs->dpms(crtc, DPMSModeOn);
> +        for (o = 0; o < xf86_config->num_output; o++) {
> +            output = xf86_config->output[o];
> +            if (output->crtc != crtc)
> +                continue;
> +
> +            output->funcs->dpms(output, DPMSModeOn);
> +        }
> +    }
> +}
> diff --git a/src/r128_cursor.c b/src/r128_cursor.c
> index b76913c..ad6752f 100644
> --- a/src/r128_cursor.c
> +++ b/src/r128_cursor.c
> @@ -59,6 +59,9 @@
>  #include "exa.h"
>  #endif
>
> +#define CURSOR_WIDTH    64
> +#define CURSOR_HEIGHT   64
> +
>  #if X_BYTE_ORDER == X_BIG_ENDIAN
>  #define P_SWAP32( a , b )                \
>         ((char *)a)[0] = ((char *)b)[3];  \
> @@ -73,84 +76,121 @@
>         ((char *)a)[3] = ((char *)b)[2]
>  #endif
>
> +void r128_crtc_show_cursor(xf86CrtcPtr crtc)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    int crtc_id = r128_crtc->crtc_id;
> +
> +    switch (crtc_id) {
> +    case 0:
> +        OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
> +        break;
> +    case 1:
> +        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN, ~R128_CRTC2_CUR_EN);
> +        break;
> +    default:
> +        return;
> +    }
> +}
>
> -/* Set cursor foreground and background colors. */
> -static void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
> +void r128_crtc_hide_cursor(xf86CrtcPtr crtc)
>  {
> -    R128InfoPtr   info      = R128PTR(pScrn);
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    R128InfoPtr info = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> +    int crtc_id = r128_crtc->crtc_id;
>
> -    if(info->IsSecondary)
> -    {
> +    switch (crtc_id) {
> +    case 0:
> +        OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
> +        break;
> +    case 1:
> +        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
> +        break;
> +    default:
> +        return;
> +    }
> +}
> +
> +void r128_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    int crtc_id = r128_crtc->crtc_id;
> +
> +    switch (crtc_id) {
> +    case 0:
> +        OUTREG(R128_CUR_CLR0, bg);
> +        OUTREG(R128_CUR_CLR1, fg);
> +        break;
> +    case 1:
>          OUTREG(R128_CUR2_CLR0, bg);
>          OUTREG(R128_CUR2_CLR1, fg);
> -    }
> -    else
> -    {
> -       OUTREG(R128_CUR_CLR0, bg);
> -       OUTREG(R128_CUR_CLR1, fg);
> +        break;
> +    default:
> +        return;
>      }
>  }
>
> -/* Set cursor position to (x,y) with offset into cursor bitmap at
> -   (xorigin,yorigin). */
> -static void R128SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
> +void r128_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
>  {
> -    R128InfoPtr           info      = R128PTR(pScrn);
> -    unsigned char         *R128MMIO = info->MMIO;
> -    xf86CursorInfoPtr     cursor    = info->cursor;
> -    int                   xorigin   = 0;
> -    int                   yorigin   = 0;
> -    int                   total_y   = pScrn->frameY1 - pScrn->frameY0;
> -
> -    if (x < 0)                        xorigin = -x;
> -    if (y < 0)                        yorigin = -y;
> -    if (y > total_y)                  y       = total_y;
> -    if (info->Flags & V_DBLSCAN)      y       *= 2;
> -    if (xorigin >= cursor->MaxWidth)  xorigin = cursor->MaxWidth - 1;
> -    if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
> -
> -    if(!info->IsSecondary)
> -    {
> -       OUTREG(R128_CUR_HORZ_VERT_OFF,  R128_CUR_LOCK | (xorigin << 16) | yorigin);
> -       OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
> -                                    | ((xorigin ? 0 : x) << 16)
> -                                    | (yorigin ? 0 : y)));
> -       OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
> -    }
> -    else
> -    {
> -        OUTREG(R128_CUR2_HORZ_VERT_OFF,  (R128_CUR2_LOCK
> -                                      | (xorigin << 16)
> -                                      | yorigin));
> -        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK
> -                                      | ((xorigin ? 0 : x) << 16)
> -                                      | (yorigin ? 0 : y)));
> -        OUTREG(R128_CUR2_OFFSET,
> -                       info->cursor_start + pScrn->fbOffset + yorigin * 16);
> +    ScrnInfoPtr           pScrn         = crtc->scrn;
> +    R128InfoPtr           info          = R128PTR(pScrn);
> +    R128CrtcPrivatePtr    r128_crtc     = crtc->driver_private;
> +    unsigned char         *R128MMIO     = info->MMIO;
> +    int                   crtc_id       = r128_crtc->crtc_id;
> +
> +    int xorigin = 0, yorigin = 0;
> +    DisplayModePtr mode = &crtc->mode;
> +
> +    if (x < 0) xorigin = -x + 1;
> +    if (y < 0) yorigin = -y + 1;
> +    if (xorigin >= CURSOR_WIDTH)  xorigin = CURSOR_WIDTH - 1;
> +    if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1;
> +
> +    if (mode->Flags & V_INTERLACE)
> +        y /= 2;
> +    else if (mode->Flags & V_DBLSCAN)
> +        y *= 2;
> +
> +    if(crtc_id == 0) {
> +        OUTREG(R128_CUR_HORZ_VERT_OFF, (R128_CUR_LOCK | (xorigin << 16) | yorigin));
> +        OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
> +        OUTREG(R128_CUR_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
> +    } else if (crtc_id == 1) {
> +        OUTREG(R128_CUR2_HORZ_VERT_OFF, (R128_CUR2_LOCK | (xorigin << 16) | yorigin));
> +        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
> +        OUTREG(R128_CUR2_OFFSET, r128_crtc->cursor_offset + pScrn->fbOffset + yorigin * 16);
>      }
>  }
>
> -/* Copy cursor image from `image' to video memory.  R128SetCursorPosition
> -   will be called after this, so we can ignore xorigin and yorigin. */
> -static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
> +void r128_crtc_load_cursor_image(xf86CrtcPtr crtc, unsigned char *src)
>  {
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +    int crtc_id = r128_crtc->crtc_id;
> +
> +
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> -    CARD32        *s        = (pointer)image;
> -    CARD32        *d        = (pointer)((CARD8*)info->FB + info->cursor_start);
> +    CARD32        *s        = (pointer)src;
> +    CARD32        *d        = (pointer)(info->FB + r128_crtc->cursor_offset + pScrn->fbOffset);
> +    CARD32        save1     = 0;
> +    CARD32        save2     = 0;
>      int           y;
> -    CARD32        save;
>
> -    if(!info->IsSecondary)
> -    {
> -       save = INREG(R128_CRTC_GEN_CNTL);
> -       OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
> -    }
> -    else
> -    {
> -        save = INREG(R128_CRTC2_GEN_CNTL);
> -        OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC2_CUR_EN);
> +    if (crtc_id == 0) {
> +       save1 = INREG(R128_CRTC_GEN_CNTL);
> +       OUTREG(R128_CRTC_GEN_CNTL, save1 & (CARD32)~R128_CRTC_CUR_EN);
> +    } else if (crtc_id == 1) {
> +       save2 = INREG(R128_CRTC2_GEN_CNTL);
> +       OUTREG(R128_CRTC2_GEN_CNTL, save2 & (CARD32)~R128_CRTC2_CUR_EN);
>      }
>
>  #if X_BYTE_ORDER == X_BIG_ENDIAN
> @@ -197,59 +237,10 @@ static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
>      }
>  #endif
>
> -    /* Set the area after the cursor to be all transparent so that we
> -       won't display corrupted cursors on the screen */
> -    for (y = 0; y < 64; y++) {
> -       *d++ = 0xffffffff; /* The AND bits */
> -       *d++ = 0xffffffff;
> -       *d++ = 0x00000000; /* The XOR bits */
> -       *d++ = 0x00000000;
> -    }
> -
> -
> -    if(!info->IsSecondary)
> -       OUTREG(R128_CRTC_GEN_CNTL, save);
> +    if (crtc_id == 0)
> +       OUTREG(R128_CRTC_GEN_CNTL, save1);
>      else
> -        OUTREG(R128_CRTC2_GEN_CNTL, save);
> -
> -}
> -
> -/* Hide hardware cursor. */
> -static void R128HideCursor(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -     if(info->IsSecondary)
> -        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
> -     else
> -       OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
> -}
> -
> -/* Show hardware cursor. */
> -static void R128ShowCursor(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    if(info->IsSecondary)
> -    {
> -         OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN,
> -               ~R128_CRTC2_CUR_EN);
> -    }
> -    else
> -    {
> -       OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
> -    }
> -}
> -
> -/* Determine if hardware cursor is in use. */
> -static Bool R128UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
> -{
> -    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
> -    R128InfoPtr info  = R128PTR(pScrn);
> -
> -    return info->cursor_start ? TRUE : FALSE;
> +        OUTREG(R128_CRTC2_GEN_CNTL, save2);
>  }
>
>  /* Initialize hardware cursor support. */
> @@ -257,77 +248,72 @@ Bool R128CursorInit(ScreenPtr pScreen)
>  {
>      ScrnInfoPtr           pScrn   = xf86ScreenToScrn(pScreen);
>      R128InfoPtr           info    = R128PTR(pScrn);
> -    xf86CursorInfoPtr     cursor;
>      FBAreaPtr             fbarea  = NULL;
>  #ifdef USE_EXA
>      ExaOffscreenArea*    osArea  = NULL;
>  #else
>      void*                osArea  = NULL;
>  #endif
> +    xf86CrtcConfigPtr     xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    CARD32                cursor_offset = 0;
> +    int                   cpp = info->CurrentLayout.pixel_bytes;
>      int                   width;
> +    int                   width_bytes;
>      int                   height;
>      int                   size;
> +    int                   size_bytes;
> +    int                   c;
>
> -    int                   cpp = info->CurrentLayout.pixel_bytes;
> -
> -    if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE;
> -
> -    cursor->MaxWidth          = 64;
> -    cursor->MaxHeight         = 64;
> -    cursor->Flags             = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
> -                                | HARDWARE_CURSOR_SHOW_TRANSPARENT
> -                                | HARDWARE_CURSOR_UPDATE_UNHIDDEN
> -#if X_BYTE_ORDER == X_LITTLE_ENDIAN
> -                                | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
> -#endif
> -                                | HARDWARE_CURSOR_INVERT_MASK
> -                                | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK
> -                                | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64
> -                                | HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
> -
> -    cursor->SetCursorColors   = R128SetCursorColors;
> -    cursor->SetCursorPosition = R128SetCursorPosition;
> -    cursor->LoadCursorImage   = R128LoadCursorImage;
> -    cursor->HideCursor        = R128HideCursor;
> -    cursor->ShowCursor        = R128ShowCursor;
> -    cursor->UseHWCursor       = R128UseHWCursor;
> -
> -    size                      = (cursor->MaxWidth/4) * cursor->MaxHeight;
> +    size                      = CURSOR_WIDTH * CURSOR_HEIGHT / 4;
> +    size_bytes                = size * 2;
>      width                     = pScrn->displayWidth;
> -    height                    = (size*2 + 1023) / pScrn->displayWidth;
> +    width_bytes               = width * (pScrn->bitsPerPixel / 8);
> +    height                    = ((size_bytes * xf86_config->num_crtc) + width_bytes - 1) / width_bytes;
>
>      if(!info->useEXA) {
>         fbarea = xf86AllocateOffscreenArea(pScreen, width, height,
>                                            16, NULL, NULL, NULL);
>
> -       if (fbarea) {
> -           info->cursor_start    = R128_ALIGN((fbarea->box.x1
> -                                           + width * fbarea->box.y1)
> -                                           * cpp, 16);
> -           info->cursor_end      = info->cursor_start + size;
> -       }
> +       if (fbarea)
> +           cursor_offset = R128_ALIGN((fbarea->box.x1 + width * fbarea->box.y1) * cpp, 16);
>      }
>  #ifdef USE_EXA
>      else {
>         osArea = exaOffscreenAlloc(pScreen, width * height, 16,
>                                    TRUE, NULL, NULL);
>
> -       if (osArea) {
> -           info->cursor_start    = osArea->offset;
> -           info->cursor_end      = osArea->offset + osArea->size;
> -       }
> +       if (osArea)
> +           cursor_offset = osArea->offset;
>      }
>  #endif
>
>      if ((!info->useEXA && !fbarea) || (info->useEXA && !osArea)) {
> -       info->cursor_start    = 0;
>         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
>                    "Hardware cursor disabled"
>                    " due to insufficient offscreen memory\n");
> +        return FALSE;
> +    } else {
> +        for (c = 0; c < xf86_config->num_crtc; c++) {
> +            xf86CrtcPtr crtc = xf86_config->crtc[c];
> +           R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +
> +            r128_crtc->cursor_offset = cursor_offset + (c * size);
> +            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
> +                      "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
> +                      (size_bytes * xf86_config->num_crtc) / 1024, c,
> +                      (unsigned int)r128_crtc->cursor_offset);
> +        }
>      }
>
> -    R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n",
> -              info->cursor_start, info->cursor_end));
> -
> -    return xf86InitCursor(pScreen, cursor);
> +    return xf86_cursors_init(pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
> +                            (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
> +                             HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
> +                             HARDWARE_CURSOR_SHOW_TRANSPARENT |
> +                             HARDWARE_CURSOR_UPDATE_UNHIDDEN |
> +#if X_BYTE_ORDER == X_LITTLE_ENDIAN
> +                             HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
> +#endif
> +                             HARDWARE_CURSOR_INVERT_MASK |
> +                             HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
> +                             HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
>  }
> diff --git a/src/r128_driver.c b/src/r128_driver.c
> index f425c3b..9205328 100644
> --- a/src/r128_driver.c
> +++ b/src/r128_driver.c
> @@ -84,6 +84,7 @@
>                                 /* X and server generic header files */
>  #include "xf86.h"
>  #include "xf86_OSproc.h"
> +#include "xf86RandR12.h"
>  #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
>  #include "xf86RAC.h"
>  #include "xf86Resources.h"
> @@ -119,11 +120,6 @@ static Bool R128CloseScreen(CLOSE_SCREEN_ARGS_DECL);
>  static Bool R128SaveScreen(ScreenPtr pScreen, int mode);
>  static void R128Save(ScrnInfoPtr pScrn);
>  static void R128Restore(ScrnInfoPtr pScrn);
> -static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
> -static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
> -                                         int PowerManagementMode, int flags);
> -static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
> -                                         int PowerManagementMode, int flags);
>
>  typedef enum {
>    OPTION_NOACCEL,
> @@ -258,6 +254,7 @@ static Bool R128MapMMIO(ScrnInfoPtr pScrn)
>                                    info->PciTag,
>                                    info->MMIOAddr,
>                                    R128_MMIOSIZE);
> +        if (!info->MMIO) return FALSE;
>  #else
>         int err = pci_device_map_range(info->PciInfo,
>                                        info->MMIOAddr,
> @@ -274,7 +271,6 @@ static Bool R128MapMMIO(ScrnInfoPtr pScrn)
>  #endif
>      }
>
> -    if (!info->MMIO) return FALSE;
>      return TRUE;
>  }
>
> @@ -402,78 +398,6 @@ void R128WaitForVerticalSync(ScrnInfoPtr pScrn)
>      }
>  }
>
> -/* Blank screen. */
> -static void R128Blank(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    if(!info->IsSecondary)
> -    {
> -        switch(info->DisplayType)
> -        {
> -        case MT_LCD:
> -            OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_DISPLAY_DIS,
> -                 ~R128_LVDS_DISPLAY_DIS);
> -           break;
> -        case MT_CRT:
> -            OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
> -           break;
> -        case MT_DFP:
> -            OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
> -           break;
> -        case MT_NONE:
> -        default:
> -           break;
> -        }
> -    }
> -    else
> -    {
> -        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~R128_CRTC2_DISP_DIS);
> -    }
> -}
> -
> -/* Unblank screen. */
> -static void R128Unblank(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    if(!info->IsSecondary)
> -    {
> -        switch(info->DisplayType)
> -        {
> -        case MT_LCD:
> -            OUTREGP(R128_LVDS_GEN_CNTL, 0,
> -                 ~R128_LVDS_DISPLAY_DIS);
> -           break;
> -        case MT_CRT:
> -            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
> -           break;
> -        case MT_DFP:
> -            OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
> -           break;
> -        case MT_NONE:
> -        default:
> -            break;
> -        }
> -    }
> -    else
> -    {
> -        switch(info->DisplayType)
> -        {
> -        case MT_LCD:
> -        case MT_DFP:
> -        case MT_CRT:
> -            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_DISP_DIS);
> -            break;
> -        case MT_NONE:
> -        default:
> -            break;
> -        }
> -    }
> -}
> -
>  /* Compute log base 2 of val. */
>  int R128MinBits(int val)
>  {
> @@ -1058,9 +982,9 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn)
>             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
>                      "Option \"Display\" ignored "
>                      "(framebuffer device determines display type)\n");
> -       else if (info->IsPrimary || info->IsSecondary)
> +       else if (!Display)
>             info->BIOSDisplay = R128_DUALHEAD;
> -       else if (!Display || !xf86NameCmp(Display, "FP"))
> +       else if (!xf86NameCmp(Display, "FP"))
>             info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
>         else if (!xf86NameCmp(Display, "BIOS"))
>             info->BIOSDisplay = INREG8(R128_BIOS_5_SCRATCH);
> @@ -1079,9 +1003,6 @@ static Bool R128PreInitConfig(ScrnInfoPtr pScrn)
>         info->BIOSDisplay     = R128_BIOS_DISPLAY_CRT;
>      }
>
> -    R128MMIO                  = NULL;
> -    R128UnmapMMIO(pScrn);
> -
>                                 /* RAM */
>      switch (info->MemCntl & 0x3) {
>      case 0:                     /* SDR SGRAM 1:1 */
> @@ -1256,6 +1177,7 @@ static Bool R128PreInitDDC(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
>  #endif
>
>      if (!xf86LoadSubModule(pScrn, "ddc")) return FALSE;
> +    if (!xf86LoadSubModule(pScrn, "i2c")) return FALSE;
>
>  #if defined(__powerpc__) || defined(__alpha__) || defined(__sparc__)
>      /* Int10 is broken on PPC and some Alphas */
> @@ -1281,468 +1203,6 @@ static Bool R128PreInitGamma(ScrnInfoPtr pScrn)
>      return TRUE;
>  }
>
> -static void
> -R128I2CGetBits(I2CBusPtr b, int *Clock, int *data)
> -{
> -    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
> -    R128InfoPtr info = R128PTR(pScrn);
> -    unsigned long val;
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    /* Get the result. */
> -    val = INREG(info->DDCReg);
> -    *Clock = (val & R128_GPIO_MONID_Y_3) != 0;
> -    *data  = (val & R128_GPIO_MONID_Y_0) != 0;
> -
> -}
> -
> -static void
> -R128I2CPutBits(I2CBusPtr b, int Clock, int data)
> -{
> -    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
> -    R128InfoPtr info = R128PTR(pScrn);
> -    unsigned long val;
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    val = INREG(info->DDCReg)
> -              & ~(CARD32)(R128_GPIO_MONID_EN_0 | R128_GPIO_MONID_EN_3);
> -    val |= (Clock ? 0:R128_GPIO_MONID_EN_3);
> -    val |= (data ? 0:R128_GPIO_MONID_EN_0);
> -    OUTREG(info->DDCReg, val);
> -}
> -
> -
> -static Bool
> -R128I2cInit(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr info = R128PTR(pScrn);
> -    if ( !xf86LoadSubModule(pScrn, "i2c") ) {
> -        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> -            "Failed to load i2c module\n");
> -               return FALSE;
> -    }
> -
> -    info->pI2CBus = xf86CreateI2CBusRec();
> -    if(!info->pI2CBus) return FALSE;
> -
> -    info->pI2CBus->BusName    = "DDC";
> -    info->pI2CBus->scrnIndex  = pScrn->scrnIndex;
> -    info->DDCReg = R128_GPIO_MONID;
> -    info->pI2CBus->I2CPutBits = R128I2CPutBits;
> -    info->pI2CBus->I2CGetBits = R128I2CGetBits;
> -    info->pI2CBus->AcknTimeout = 5;
> -
> -    if (!xf86I2CBusInit(info->pI2CBus)) {
> -        return FALSE;
> -    }
> -    return TRUE;
> -}
> -
> -/* return TRUE is a DFP is indeed connected to a DVI port */
> -static Bool R128GetDFPInfo(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr info  = R128PTR(pScrn);
> -    int i;
> -    xf86MonPtr MonInfo = NULL;
> -    xf86MonPtr ddc;
> -    unsigned char *R128MMIO = info->MMIO;
> -
> -    if(!R128I2cInit(pScrn)){
> -        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> -                  "I2C initialization failed!\n");
> -    }
> -
> -    OUTREG(info->DDCReg, (INREG(info->DDCReg)
> -           | R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3));
> -
> -    OUTREG(info->DDCReg, INREG(info->DDCReg)
> -           & ~(CARD32)(R128_GPIO_MONID_A_0 | R128_GPIO_MONID_A_3));
> -
> -    MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), info->pI2CBus);
> -    if(!MonInfo) {
> -        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> -                   "No DFP detected\n");
> -        return FALSE;
> -    }
> -    xf86SetDDCproperties(pScrn, MonInfo);
> -    ddc = pScrn->monitor->DDC;
> -
> -    for(i=0; i<4; i++)
> -    {
> -        if((ddc->det_mon[i].type == 0) &&
> -         (ddc->det_mon[i].section.d_timings.h_active > 0) &&
> -         (ddc->det_mon[i].section.d_timings.v_active > 0))
> -        {
> -            info->PanelXRes =
> -                ddc->det_mon[i].section.d_timings.h_active;
> -            info->PanelYRes =
> -                ddc->det_mon[i].section.d_timings.v_active;
> -
> -            info->HOverPlus =
> -                ddc->det_mon[i].section.d_timings.h_sync_off;
> -            info->HSyncWidth =
> -                ddc->det_mon[i].section.d_timings.h_sync_width;
> -            info->HBlank =
> -                ddc->det_mon[i].section.d_timings.h_blanking;
> -            info->VOverPlus =
> -                ddc->det_mon[i].section.d_timings.v_sync_off;
> -            info->VSyncWidth =
> -                ddc->det_mon[i].section.d_timings.v_sync_width;
> -            info->VBlank =
> -                ddc->det_mon[i].section.d_timings.v_blanking;
> -        }
> -    }
> -    return TRUE;
> -}
> -
> -
> -static void R128SetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
> -{
> -    int i;
> -    xf86MonPtr ddc = pScrn->monitor->DDC;
> -    if(flag)  /*HSync*/
> -    {
> -        for(i=0; i<4; i++)
> -        {
> -            if(ddc->det_mon[i].type == DS_RANGES)
> -            {
> -                pScrn->monitor->nHsync = 1;
> -                pScrn->monitor->hsync[0].lo =
> -                    ddc->det_mon[i].section.ranges.min_h;
> -                pScrn->monitor->hsync[0].hi =
> -                    ddc->det_mon[i].section.ranges.max_h;
> -                return;
> -            }
> -        }
> -        /*if no sync ranges detected in detailed timing table,
> -          let's try to derive them from supported VESA modes
> -          Are we doing too much here!!!?
> -        **/
> -        i = 0;
> -        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 35.2;
> -            i++;
> -        }
> -        if(ddc->timings1.t1 & 0x04) /*640x480 at 75*/
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 37.5;
> -            i++;
> -        }
> -        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01))
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 37.9;
> -            i++;
> -        }
> -        if(ddc->timings1.t2 & 0x40)
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 46.9;
> -            i++;
> -        }
> -        if((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08))
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 48.1;
> -            i++;
> -        }
> -        if(ddc->timings1.t2 & 0x04)
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 56.5;
> -            i++;
> -        }
> -        if(ddc->timings1.t2 & 0x02)
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 60.0;
> -            i++;
> -        }
> -        if(ddc->timings1.t2 & 0x01)
> -        {
> -            pScrn->monitor->hsync[i].lo =
> -                pScrn->monitor->hsync[i].hi = 64.0;
> -            i++;
> -        }
> -        pScrn->monitor->nHsync = i;
> -    }
> -    else      /*Vrefresh*/
> -    {
> -        for(i=0; i<4; i++)
> -        {
> -            if(ddc->det_mon[i].type == DS_RANGES)
> -            {
> -                pScrn->monitor->nVrefresh = 1;
> -                pScrn->monitor->vrefresh[0].lo =
> -                    ddc->det_mon[i].section.ranges.min_v;
> -                pScrn->monitor->vrefresh[0].hi =
> -                    ddc->det_mon[i].section.ranges.max_v;
> -                return;
> -            }
> -        }
> -        i = 0;
> -        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
> -        {
> -            pScrn->monitor->vrefresh[i].lo =
> -                pScrn->monitor->vrefresh[i].hi = 56;
> -            i++;
> -        }
> -        if((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08))
> -        {
> -            pScrn->monitor->vrefresh[i].lo =
> -                pScrn->monitor->vrefresh[i].hi = 60;
> -            i++;
> -        }
> -        if(ddc->timings1.t2 & 0x04)
> -        {
> -            pScrn->monitor->vrefresh[i].lo =
> -                pScrn->monitor->vrefresh[i].hi = 70;
> -            i++;
> -        }
> -        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80))
> -        {
> -            pScrn->monitor->vrefresh[i].lo =
> -                pScrn->monitor->vrefresh[i].hi = 72;
> -            i++;
> -        }
> -        if((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40)
> -           || (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01))
> -        {
> -            pScrn->monitor->vrefresh[i].lo =
> -                pScrn->monitor->vrefresh[i].hi = 75;
> -            i++;
> -        }
> -        pScrn->monitor->nVrefresh = i;
> -    }
> -}
> -
> -/***********
> -   free's xf86ValidateModes routine deosn't work well with DFPs
> -   here is our own validation routine. All modes between
> -   640<=XRes<=MaxRes and 480<=YRes<=MaxYRes will be permitted.
> -   NOTE: RageProII doesn't support rmx, can only work with the
> -         standard modes the monitor can support (scale).
> -************/
> -
> -static int R128ValidateFPModes(ScrnInfoPtr pScrn)
> -{
> -    int i, j, count=0, width, height;
> -    R128InfoPtr info = R128PTR(pScrn);
> -    DisplayModePtr last = NULL, new = NULL, first = NULL;
> -    xf86MonPtr ddc;
> -
> -    /* Free any allocated modes during configuration. We don't need them*/
> -    while (pScrn->modes)
> -    {
> -           xf86DeleteMode(&pScrn->modes, pScrn->modes);
> -    }
> -    while (pScrn->modePool)
> -    {
> -           xf86DeleteMode(&pScrn->modePool, pScrn->modePool);
> -    }
> -
> -    pScrn->virtualX = pScrn->display->virtualX;
> -    pScrn->virtualY = pScrn->display->virtualY;
> -
> -    /* If no mode specified in config, we use native resolution*/
> -    if(!pScrn->display->modes[0])
> -    {
> -        pScrn->display->modes[0] = xnfalloc(16);
> -        sprintf(pScrn->display->modes[0], "%dx%d",
> -               info->PanelXRes, info->PanelYRes);
> -    }
> -
> -    for(i=0; pScrn->display->modes[i] != NULL; i++)
> -    {
> -        if (sscanf(pScrn->display->modes[i], "%dx%d", &width, &height) == 2)
> -        {
> -
> -            if(width < 640 || width > info->PanelXRes ||
> -               height < 480 || height > info->PanelYRes)
> -            {
> -                xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
> -                    "Mode %s is out of range.\n"
> -                    "Valid mode should be between 640x480-%dx%d\n",
> -                    pScrn->display->modes[i], info->PanelXRes, info->PanelYRes);
> -                continue;
> -            }
> -
> -            new = xnfcalloc(1, sizeof(DisplayModeRec));
> -            new->prev = last;
> -            new->name = xnfalloc(strlen(pScrn->display->modes[i]) + 1);
> -            strcpy(new->name, pScrn->display->modes[i]);
> -            new->HDisplay = new->CrtcHDisplay = width;
> -            new->VDisplay = new->CrtcVDisplay = height;
> -
> -            ddc = pScrn->monitor->DDC;
> -            for(j=0; j<DET_TIMINGS; j++)
> -            {
> -                /*We use native mode clock only*/
> -                if(ddc->det_mon[j].type == 0){
> -                    new->Clock = ddc->det_mon[j].section.d_timings.clock / 1000;
> -                    break;
> -                }
> -            }
> -
> -            if(new->prev) new->prev->next = new;
> -            last = new;
> -            if(!first) first = new;
> -            pScrn->display->virtualX =
> -            pScrn->virtualX = MAX(pScrn->virtualX, width);
> -            pScrn->display->virtualY =
> -            pScrn->virtualY = MAX(pScrn->virtualY, height);
> -            count++;
> -        }
> -        else
> -        {
> -            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
> -                "Mode name %s is invalid\n", pScrn->display->modes[i]);
> -            continue;
> -        }
> -   }
> -
> -   if(last)
> -   {
> -       last->next = first;
> -       first->prev = last;
> -       pScrn->modes = first;
> -
> -       /*FIXME: May need to validate line pitch here*/
> -       {
> -           int dummy = 0;
> -           switch(pScrn->depth / 8)
> -           {
> -              case 1:
> -                  dummy = 128 - pScrn->virtualX % 128;
> -                  break;
> -              case 2:
> -                  dummy = 32 - pScrn->virtualX % 32;
> -                  break;
> -              case 3:
> -              case 4:
> -                  dummy = 16 - pScrn->virtualX % 16;
> -           }
> -           pScrn->displayWidth = pScrn->virtualX + dummy;
> -       }
> -
> -   }
> -
> -   return count;
> -}
> -
> -
> -/* This is called by R128PreInit to validate modes and compute parameters
> -   for all of the valid modes. */
> -static Bool R128PreInitModes(ScrnInfoPtr pScrn)
> -{
> -    R128InfoPtr   info = R128PTR(pScrn);
> -    ClockRangePtr clockRanges;
> -    int           modesFound;
> -
> -    if(info->isDFP) {
> -        R128MapMem(pScrn);
> -        info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
> -        /* validate if DFP really connected. */
> -        if(!R128GetDFPInfo(pScrn)) {
> -            info->isDFP = FALSE;
> -            info->BIOSDisplay = R128_BIOS_DISPLAY_CRT;
> -        } else if(!info->isPro2) {
> -            /* RageProII doesn't support rmx, we can't use native-mode
> -               stretching for other non-native modes. It will rely on
> -               whatever VESA modes monitor can support. */
> -            modesFound = R128ValidateFPModes(pScrn);
> -            if(modesFound < 1) {
> -                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
> -                     "No valid mode found for this DFP/LCD\n");
> -                 R128UnmapMem(pScrn);
> -                 return FALSE;
> -
> -            }
> -        }
> -        R128UnmapMem(pScrn);
> -    }
> -
> -    if(!info->isDFP || info->isPro2) {
> -                               /* Get mode information */
> -        pScrn->progClock                   = TRUE;
> -        clockRanges                        = xnfcalloc(sizeof(*clockRanges), 1);
> -        clockRanges->next                  = NULL;
> -        clockRanges->minClock              = info->pll.min_pll_freq;
> -        clockRanges->maxClock              = info->pll.max_pll_freq * 10;
> -        clockRanges->clockIndex            = -1;
> -        if (info->HasPanelRegs || info->isDFP) {
> -            clockRanges->interlaceAllowed  = FALSE;
> -            clockRanges->doubleScanAllowed = FALSE;
> -        } else {
> -            clockRanges->interlaceAllowed  = TRUE;
> -            clockRanges->doubleScanAllowed = TRUE;
> -        }
> -
> -        if(pScrn->monitor->DDC) {
> -        /*if we still don't know sync range yet, let's try EDID.
> -          Note that, since we can have dual heads, the Xconfigurator
> -          may not be able to probe both monitors correctly through
> -          vbe probe function (R128ProbeDDC). Here we provide an
> -          additional way to auto-detect sync ranges if they haven't
> -          been added to XF86Config manually.
> -        **/
> -            if(pScrn->monitor->nHsync <= 0)
> -                R128SetSyncRangeFromEdid(pScrn, 1);
> -            if(pScrn->monitor->nVrefresh <= 0)
> -                R128SetSyncRangeFromEdid(pScrn, 0);
> -        }
> -
> -        modesFound = xf86ValidateModes(pScrn,
> -                                  pScrn->monitor->Modes,
> -                                  pScrn->display->modes,
> -                                  clockRanges,
> -                                  NULL,        /* linePitches */
> -                                  8 * 64,      /* minPitch */
> -                                  8 * 1024,    /* maxPitch */
> -/*
> - * ATI docs say pitchInc must be 8 * 64, but this doesn't permit a pitch of
> - * 800 bytes, which is known to work on the Rage128 LF on clamshell iBooks
> - */
> -                                  8 * 32,      /* pitchInc */
> -                                  128,         /* minHeight */
> -                                  2048,        /* maxHeight */
> -                                  pScrn->display->virtualX,
> -                                  pScrn->display->virtualY,
> -                                  info->FbMapSize,
> -                                  LOOKUP_BEST_REFRESH);
> -
> -        if (modesFound < 1 && info->FBDev) {
> -               fbdevHWUseBuildinMode(pScrn);
> -               pScrn->displayWidth = fbdevHWGetLineLength(pScrn)/(pScrn->bitsPerPixel/8);
> -               modesFound = 1;
> -        }
> -
> -        if (modesFound == -1) return FALSE;
> -        xf86PruneDriverModes(pScrn);
> -        if (!modesFound || !pScrn->modes) {
> -            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
> -            return FALSE;
> -        }
> -        xf86SetCrtcForModes(pScrn, 0);
> -    }
> -                               /* Set DPI */
> -    pScrn->currentMode = pScrn->modes;
> -    xf86PrintModes(pScrn);
> -
> -    xf86SetDpi(pScrn, 0, 0);
> -
> -                               /* Get ScreenInit function */
> -    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
> -
> -    info->CurrentLayout.displayWidth = pScrn->displayWidth;
> -    info->CurrentLayout.mode = pScrn->currentMode;
> -
> -    return TRUE;
> -}
> -
>  /* This is called by R128PreInit to initialize the hardware cursor. */
>  static Bool R128PreInitCursor(ScrnInfoPtr pScrn)
>  {
> @@ -1885,6 +1345,43 @@ static Bool R128PreInitDRI(ScrnInfoPtr pScrn)
>  }
>  #endif
>
> +static Bool R128PreInitControllers(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
> +{
> +    R128InfoPtr info = R128PTR(pScrn);
> +    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    int i;
> +    int mask;
> +    int found = 0;
> +
> +    if (info->IsPrimary)
> +        mask = 1;
> +    else if (info->IsSecondary)
> +        mask = 2;
> +    else
> +        mask = 3;
> +
> +    if (!R128GetBIOSParameters(pScrn, pInt10))
> +        return FALSE;
> +
> +    if (!R128GetPLLParameters(pScrn))
> +        return FALSE;
> +
> +    if (!R128AllocateControllers(pScrn, mask))
> +        return FALSE;
> +
> +    if (!R128SetupConnectors(pScrn))
> +        return FALSE;
> +
> +    for (i = 0; i < config->num_output; i++) {
> +        xf86OutputPtr output = config->output[i];
> +
> +        output->status = (*output->funcs->detect) (output);
> +        if (output->status == XF86OutputStatusConnected)
> +            found++;
> +    }
> +    return !!found;
> +}
> +
>  static void
>  R128ProbeDDC(ScrnInfoPtr pScrn, int indx)
>  {
> @@ -1899,6 +1396,17 @@ R128ProbeDDC(ScrnInfoPtr pScrn, int indx)
>  #endif
>  }
>
> +static Bool R128CRTCResize(ScrnInfoPtr pScrn, int width, int height)
> +{
> +    pScrn->virtualX = width;
> +    pScrn->virtualY = height;
> +    return TRUE;
> +}
> +
> +static const xf86CrtcConfigFuncsRec R128CRTCResizeFuncs = {
> +    R128CRTCResize
> +};
> +
>  /* R128PreInit is called once at server startup. */
>  Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>  {
> @@ -1976,6 +1484,9 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>  #endif
>      pScrn->monitor     = pScrn->confScreen->monitor;
>
> +    /* Allocate an xf86CrtcConfig */
> +    xf86CrtcConfigInit(pScrn, &R128CRTCResizeFuncs);
> +
>      if (!R128PreInitVisual(pScrn))    goto fail;
>
>                                 /* We can't do this until we have a
> @@ -2016,8 +1527,6 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>                 "module load skipped\n");
>  #endif
>
> -
> -
>      if (!R128PreInitWeight(pScrn))    goto fail;
>
>      if(xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, &(info->videoKey))) {
> @@ -2053,20 +1562,30 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>      }
>
>      if (!info->FBDev)
> -       if (!R128PreInitInt10(pScrn, &pInt10)) goto fail;
> -
> -    if (!R128PreInitConfig(pScrn))             goto fail;
> +       if (!R128PreInitInt10(pScrn, &pInt10))  goto fail;
>
> -    if (!R128GetBIOSParameters(pScrn, pInt10)) goto fail;
> +    if (!R128PreInitConfig(pScrn))              goto fail;
>
> -    if (!R128GetPLLParameters(pScrn))          goto fail;
> +    xf86CrtcSetSizeRange(pScrn, 320, 200, 4096, 4096);
>
>      /* Don't fail on this one */
> -    R128PreInitDDC(pScrn, pInt10);
> +    info->DDC = R128PreInitDDC(pScrn, pInt10);
>
> -    if (!R128PreInitGamma(pScrn))              goto fail;
> +    if (!R128PreInitControllers(pScrn, pInt10)) goto fail;
> +
> +    if (!xf86InitialConfiguration(pScrn, TRUE)) {
> +        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
> +        goto fail;
> +    }
> +    pScrn->displayWidth = (pScrn->virtualX + 63) & ~63;
>
> -    if (!R128PreInitModes(pScrn))              goto fail;
> +    /* Set display resolution */
> +    xf86SetDpi(pScrn, 0, 0);
> +
> +    /* Get ScreenInit function */
> +    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
> +
> +    if (!R128PreInitGamma(pScrn))              goto fail;
>
>      if (!R128PreInitCursor(pScrn))             goto fail;
>
> @@ -2074,6 +1593,18 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>      if (!R128PreInitDRI(pScrn))                goto fail;
>  #endif
>
> +    info->CurrentLayout.displayWidth = pScrn->displayWidth;
> +
> +    if (!xf86RandR12PreInit(pScrn)) {
> +        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n");
> +        goto fail;
> +    }
> +
> +    if (pScrn->modes == NULL) {
> +        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
> +        goto fail;
> +    }
> +
>                                 /* Free the video bios (if applicable) */
>      if (info->VBIOS) {
>         free(info->VBIOS);
> @@ -2084,6 +1615,9 @@ Bool R128PreInit(ScrnInfoPtr pScrn, int flags)
>      if (pInt10)
>         xf86FreeInt10(pInt10);
>
> +    if (info->MMIO) R128UnmapMMIO(pScrn);
> +    info->MMIO = NULL;
> +
>      xf86DrvMsg(pScrn->scrnIndex, X_NOTICE,
>         "For information on using the multimedia capabilities\n\tof this"
>         " adapter, please see http://gatos.sf.net.\n");
> @@ -2116,56 +1650,66 @@ static void R128LoadPalette(ScrnInfoPtr pScrn, int numColors,
>                             int *indices, LOCO *colors, VisualPtr pVisual)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -    int           i, j;
> -    int           idx;
> -    unsigned char r, g, b;
> -
> -    /* If the second monitor is connected, we also
> -       need to deal with the secondary palette*/
> -    if (info->IsSecondary) j = 1;
> -    else j = 0;
> -
> -    PAL_SELECT(j);
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +    int i, j;
> +    int c, index;
> +    CARD16 lut_r[256], lut_g[256], lut_b[256];
> +
> +    for (c = 0; c < xf86_config->num_crtc; c++) {
> +        xf86CrtcPtr crtc = xf86_config->crtc[c];
> +        R128CrtcPrivatePtr r128_crtc = crtc->driver_private;
> +
> +        for (i = 0 ; i < 256; i++) {
> +            lut_r[i] = r128_crtc->lut_r[i] << 8;
> +            lut_g[i] = r128_crtc->lut_g[i] << 8;
> +            lut_b[i] = r128_crtc->lut_b[i] << 8;
> +        }
>
> +        switch (info->CurrentLayout.depth) {
> +        case 15:
> +            for (i = 0; i < numColors; i++) {
> +                index = indices[i];
> +                for (j = 0; j < 8; j++) {
> +                    lut_r[index * 8 + j] = colors[index].red << 8;
> +                    lut_g[index * 8 + j] = colors[index].green << 8;
> +                    lut_b[index * 8 + j] = colors[index].blue << 8;
> +                }
> +            }
> +        case 16:
> +            for (i = 0; i < numColors; i++) {
> +                index = indices[i];
> +
> +                /* XXX: The old version of R128LoadPalette did not do this and
> +                 * the old version of RADEONLoadPalette has a comment asking why.
> +                 */
> +                if (i <= 31) {
> +                    for (j = 0; j < 8; j++) {
> +                        lut_r[index * 8 + j] = colors[index].red << 8;
> +                        lut_b[index * 8 + j] = colors[index].blue << 8;
> +                    }
> +                }
>
> -    /* Select palette 0 (main CRTC) if using FP-enabled chip */
> -    /*if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);*/
> +                for (j = 0; j < 4; j++) {
> +                    lut_g[index * 4 + j] = colors[index].green << 8;
> +                }
> +            }
> +        default:
> +            for (i = 0; i < numColors; i++) {
> +                index = indices[i];
> +                lut_r[index] = colors[index].red << 8;
> +                lut_g[index] = colors[index].green << 8;
> +                lut_b[index] = colors[index].blue << 8;
> +            }
> +            break;
> +        }
>
> -    if (info->CurrentLayout.depth == 15) {
> -       /* 15bpp mode.  This sends 32 values. */
> -       for (i = 0; i < numColors; i++) {
> -           idx = indices[i];
> -           r   = colors[idx].red;
> -           g   = colors[idx].green;
> -           b   = colors[idx].blue;
> -           OUTPAL(idx * 8, r, g, b);
> -       }
> -    }
> -    else if (info->CurrentLayout.depth == 16) {
> -       /* 16bpp mode.  This sends 64 values. */
> -                               /* There are twice as many green values as
> -                                  there are values for red and blue.  So,
> -                                  we take each red and blue pair, and
> -                                  combine it with each of the two green
> -                                  values. */
> -       for (i = 0; i < numColors; i++) {
> -           idx = indices[i];
> -           r   = colors[idx / 2].red;
> -           g   = colors[idx].green;
> -           b   = colors[idx / 2].blue;
> -           OUTPAL(idx * 4, r, g, b);
> -       }
> -    }
> -    else {
> -       /* 8bpp mode.  This sends 256 values. */
> -       for (i = 0; i < numColors; i++) {
> -           idx = indices[i];
> -           r   = colors[idx].red;
> -           b   = colors[idx].blue;
> -           g   = colors[idx].green;
> -           OUTPAL(idx, r, g, b);
> -       }
> +        /* Make the change through RandR */
> +#ifdef RANDR_12_INTERFACE
> +        if (crtc->randr_crtc)
> +            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
> +        else
> +#endif
> +        crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
>      }
>  }
>
> @@ -2296,14 +1840,6 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
>      info->PaletteSavedOnVT = FALSE;
>
>      R128Save(pScrn);
> -    if (info->FBDev) {
> -       if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE;
> -    } else {
> -       if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
> -    }
> -
> -    R128SaveScreen(pScreen, SCREEN_SAVER_ON);
> -    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
>
>                                 /* Visual setup */
>      miClearVisualTypes();
> @@ -2701,6 +2237,19 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
>  #endif
>      }
>
> +    pScrn->vtSema = TRUE;
> +    /* xf86CrtcRotate accesses pScrn->pScreen */
> +    pScrn->pScreen = pScreen;
> +
> +    if (info->FBDev) {
> +       if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE;
> +    } else {
> +       if (!xf86SetDesiredModes(pScrn)) return FALSE;
> +    }
> +
> +    R128SaveScreen(pScreen, SCREEN_SAVER_ON);
> +    //pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
> +
>                                 /* DGA setup */
>      R128DGAInit(pScreen);
>
> @@ -2737,28 +2286,11 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
>         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using software cursor\n");
>      }
>
> -                               /* Colormap setup */
> -    if (!miCreateDefColormap(pScreen)) return FALSE;
> -    if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8,
> -                            (info->FBDev ? fbdevHWLoadPaletteWeak() :
> -                            R128LoadPalette), NULL,
> -                            CMAP_PALETTED_TRUECOLOR
> -                            | CMAP_RELOAD_ON_MODE_SWITCH
> -#if 0 /* This option messes up text mode! (eich at suse.de) */
> -                            | CMAP_LOAD_EVEN_IF_OFFSCREEN
> -#endif
> -                            )) return FALSE;
> -
>      /* DPMS setup - FIXME: also for mirror mode in non-fbdev case? - Michel */
>      if (info->FBDev)
>         xf86DPMSInit(pScreen, fbdevHWDPMSSetWeak(), 0);
> -
> -    else {
> -       if (info->DisplayType == MT_LCD)
> -           xf86DPMSInit(pScreen, R128DisplayPowerManagementSetLCD, 0);
> -       else
> -           xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0);
> -    }
> +    else
> +        xf86DPMSInit(pScreen, xf86DPMSSet, 0);
>
>      if (!info->IsSecondary)
>         R128InitVideo(pScreen);
> @@ -2793,11 +2325,25 @@ Bool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
>      info->BlockHandler = pScreen->BlockHandler;
>      pScreen->BlockHandler = R128BlockHandler;
>
> +    if (!xf86CrtcScreenInit(pScreen)) return FALSE;
> +
> +                               /* Colormap setup */
> +    if (!miCreateDefColormap(pScreen)) return FALSE;
> +    if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8,
> +                            (info->FBDev ? fbdevHWLoadPaletteWeak() :
> +                            R128LoadPalette), NULL,
> +                            CMAP_PALETTED_TRUECOLOR
> +                            | CMAP_RELOAD_ON_MODE_SWITCH
> +#if 0 /* This option messes up text mode! (eich at suse.de) */
> +                            | CMAP_LOAD_EVEN_IF_OFFSCREEN
> +#endif
> +                            )) return FALSE;
> +
>      return TRUE;
>  }
>
>  /* Write common registers (initialized to 0). */
> -static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -2821,7 +2367,7 @@ static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  }
>
>  /* Write CRTC registers. */
> -static void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -2844,7 +2390,7 @@ static void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  }
>
>  /* Write CRTC2 registers. */
> -static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
> +void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
>                                        R128SavePtr restore)
>  {
>      R128InfoPtr info        = R128PTR(pScrn);
> @@ -2863,7 +2409,7 @@ static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
>  }
>
>  /* Write flat panel registers */
> -static void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -2936,7 +2482,7 @@ static void R128PLL2WriteUpdate(ScrnInfoPtr pScrn)
>  }
>
>  /* Write PLL registers. */
> -static void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -2999,7 +2545,7 @@ static void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  }
>
>  /* Write PLL2 registers. */
> -static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr info        = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -3068,7 +2614,7 @@ static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
>  }
>
>  /* Write DDA registers. */
> -static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -3078,7 +2624,7 @@ static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
>  }
>
>  /* Write DDA registers. */
> -static void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
> +void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
>  {
>      R128InfoPtr   info      = R128PTR(pScrn);
>      unsigned char *R128MMIO = info->MMIO;
> @@ -3087,126 +2633,6 @@ static void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
>      OUTREG(R128_DDA2_ON_OFF, restore->dda2_on_off);
>  }
>
> -/* Write palette data. */
> -static void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -    int           i;
> -
> -    if (!restore->palette_valid) return;
> -
> -    PAL_SELECT(1);
> -    OUTPAL_START(0);
> -    for (i = 0; i < 256; i++) {
> -       R128WaitForFifo(pScrn, 32); /* delay */
> -       OUTPAL_NEXT_CARD32(restore->palette2[i]);
> -    }
> -
> -    PAL_SELECT(0);
> -    OUTPAL_START(0);
> -    for (i = 0; i < 256; i++) {
> -       R128WaitForFifo(pScrn, 32); /* delay */
> -       OUTPAL_NEXT_CARD32(restore->palette[i]);
> -    }
> -
> -}
> -
> -/* Write out state to define a new video mode.  */
> -static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
> -{
> -    R128InfoPtr info = R128PTR(pScrn);
> -    DevUnion* pPriv;
> -    R128EntPtr pR128Ent;
> -    static R128SaveRec restore0;
> -
> -    R128TRACE(("R128RestoreMode(%p)\n", restore));
> -    if(!info->HasCRTC2)
> -    {
> -       R128RestoreCommonRegisters(pScrn, restore);
> -        R128RestoreDDARegisters(pScrn, restore);
> -       R128RestoreCrtcRegisters(pScrn, restore);
> -        if((info->DisplayType == MT_DFP) ||
> -           (info->DisplayType == MT_LCD))
> -        {
> -           R128RestoreFPRegisters(pScrn, restore);
> -        }
> -        R128RestorePLLRegisters(pScrn, restore);
> -        return;
> -    }
> -
> -    pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
> -                   getR128EntityIndex());
> -    pR128Ent = pPriv->ptr;
> -
> -
> -    /*****
> -      When changing mode with Dual-head card (VE/M6), care must
> -      be taken for the special order in setting registers. CRTC2 has
> -      to be set before changing CRTC_EXT register.
> -      In the dual-head setup, X server calls this routine twice with
> -      primary and secondary pScrn pointers respectively. The calls
> -      can come with different order. Regardless the order of X server issuing
> -      the calls, we have to ensure we set registers in the right order!!!
> -      Otherwise we may get a blank screen.
> -    *****/
> -
> -    if(info->IsSecondary)
> -    {
> -       if (!pR128Ent->RestorePrimary  && !info->SwitchingMode)
> -           R128RestoreCommonRegisters(pScrn, restore);
> -        R128RestoreDDA2Registers(pScrn, restore);
> -        R128RestoreCrtc2Registers(pScrn, restore);
> -        R128RestorePLL2Registers(pScrn, restore);
> -
> -       if(info->SwitchingMode) return;
> -
> -        pR128Ent->IsSecondaryRestored = TRUE;
> -
> -        if(pR128Ent->RestorePrimary)
> -        {
> -            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn);
> -            pR128Ent->RestorePrimary = FALSE;
> -
> -            R128RestoreCrtcRegisters(pScrn, &restore0);
> -            if((info0->DisplayType == MT_DFP) ||
> -               (info0->DisplayType == MT_LCD))
> -            {
> -                R128RestoreFPRegisters(pScrn, &restore0);
> -            }
> -
> -            R128RestorePLLRegisters(pScrn, &restore0);
> -            pR128Ent->IsSecondaryRestored = FALSE;
> -
> -        }
> -    }
> -    else
> -    {
> -       if (!pR128Ent->IsSecondaryRestored)
> -            R128RestoreCommonRegisters(pScrn, restore);
> -        R128RestoreDDARegisters(pScrn, restore);
> -        if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
> -            || info->SwitchingMode)
> -        {
> -           pR128Ent->IsSecondaryRestored = FALSE;
> -            R128RestoreCrtcRegisters(pScrn, restore);
> -            if((info->DisplayType == MT_DFP) ||
> -               (info->DisplayType == MT_LCD))
> -            {
> -               R128RestoreFPRegisters(pScrn, restore);
> -            }
> -            R128RestorePLLRegisters(pScrn, restore);
> -        }
> -        else
> -        {
> -            memcpy(&restore0, restore, sizeof(restore0));
> -            pR128Ent->RestorePrimary = TRUE;
> -        }
> -    }
> -
> -    R128RestorePalette(pScrn, restore);
> -}
> -
>  /* Read common registers. */
>  static void R128SaveCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
>  {
> @@ -3450,9 +2876,19 @@ static void R128Restore(ScrnInfoPtr pScrn)
>          OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index);
>          OUTREG(R128_GEN_RESET_CNTL,   restore->gen_reset_cntl);
>          OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
> +
> +        R128RestoreCommonRegisters(pScrn, restore);
> +        if (info->HasCRTC2) {
> +            R128RestoreDDA2Registers(pScrn, restore);
> +            R128RestoreCrtc2Registers(pScrn, restore);
> +            R128RestorePLL2Registers(pScrn, restore);
> +        }
> +        R128RestoreDDARegisters(pScrn, restore);
> +        R128RestoreCrtcRegisters(pScrn, restore);
> +        R128RestorePLLRegisters(pScrn, restore);
> +        R128RestoreFPRegisters(pScrn, restore);
>      }
>
> -    R128RestoreMode(pScrn, restore);
>  #ifdef WITH_VGAHW
>      if (info->VGAAccess) {
>          vgaHWPtr hwp = VGAHWPTR(pScrn);
> @@ -3492,7 +2928,7 @@ static void R128Restore(ScrnInfoPtr pScrn)
>  }
>
>  /* Define common registers for requested video mode. */
> -static void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
> +void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
>  {
>      save->ovr_clr            = 0;
>      save->ovr_wid_left_right = 0;
> @@ -3518,8 +2954,64 @@ static void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
>         save->bus_cntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN;
>  }
>
> +Bool R128InitCrtcBase(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128InfoPtr info  = R128PTR(pScrn);
> +    int offset = y * info->CurrentLayout.displayWidth + x;
> +    int Base = pScrn->fbOffset;
> +
> +    switch (info->CurrentLayout.pixel_code) {
> +    case 15:
> +    case 16: offset *= 2; break;
> +    case 24: offset *= 3; break;
> +    case 32: offset *= 4; break;
> +    }
> +    Base += offset;
> +
> +    if (crtc->rotatedData != NULL)
> +        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
> +
> +    Base &= ~7;                 /* 3 lower bits are always 0 */
> +    if (info->CurrentLayout.pixel_code == 24)
> +       Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
> +
> +    save->crtc_offset = Base;
> +    save->crtc_offset_cntl = 0;
> +
> +    return TRUE;
> +}
> +
> +Bool R128InitCrtc2Base(xf86CrtcPtr crtc, R128SavePtr save, int x, int y)
> +{
> +    ScrnInfoPtr pScrn = crtc->scrn;
> +    R128InfoPtr info  = R128PTR(pScrn);
> +    int offset = y * info->CurrentLayout.displayWidth + x;
> +    int Base = pScrn->fbOffset;
> +
> +    switch (info->CurrentLayout.pixel_code) {
> +    case 15:
> +    case 16: offset *= 2; break;
> +    case 24: offset *= 3; break;
> +    case 32: offset *= 4; break;
> +    }
> +    Base += offset;
> +
> +    if (crtc->rotatedData != NULL)
> +        Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
> +
> +    Base &= ~7;                 /* 3 lower bits are always 0 */
> +    if (info->CurrentLayout.pixel_code == 24)
> +       Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
> +
> +    save->crtc2_offset = Base;
> +    save->crtc2_offset_cntl = 0;
> +
> +    return TRUE;
> +}
> +
>  /* Define CRTC registers for requested video mode. */
> -static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
> +Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>                                   DisplayModePtr mode, R128InfoPtr info)
>  {
>      int    format;
> @@ -3633,8 +3125,6 @@ static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>                                  | ((mode->Flags & V_NVSYNC)
>                                     ? R128_CRTC_V_SYNC_POL
>                                     : 0));
> -    save->crtc_offset      = 0;
> -    save->crtc_offset_cntl = 0;
>      save->crtc_pitch       = info->CurrentLayout.displayWidth / 8;
>
>      R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
> @@ -3654,7 +3144,7 @@ static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>  }
>
>  /* Define CRTC2 registers for requested video mode. */
> -static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
> +Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>                                   DisplayModePtr mode, R128InfoPtr info)
>  {
>      int    format;
> @@ -3727,10 +3217,6 @@ static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>                                  | ((mode->Flags & V_NVSYNC)
>                                     ? R128_CRTC2_V_SYNC_POL
>                                     : 0));
> -
> -    save->crtc2_offset      = 0;
> -    save->crtc2_offset_cntl = 0;
> -
>      save->crtc2_pitch       = info->CurrentLayout.displayWidth / 8;
>
>      R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
> @@ -3740,7 +3226,7 @@ static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>  }
>
>  /* Define CRTC registers for requested video mode. */
> -static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
> +void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
>                                 DisplayModePtr mode, R128InfoPtr info)
>  {
>      int   xres = mode->CrtcHDisplay;
> @@ -3853,7 +3339,7 @@ static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
>  }
>
>  /* Define PLL registers for requested video mode. */
> -static void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
> +void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>                                 R128PLLPtr pll, double dot_clock)
>  {
>      unsigned long freq = dot_clock * 100;
> @@ -3905,7 +3391,7 @@ static void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>  }
>
>  /* Define PLL2 registers for requested video mode. */
> -static void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
> +void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>                                    R128PLLPtr pll, double dot_clock)
>  {
>      unsigned long freq = dot_clock * 100;
> @@ -3957,7 +3443,7 @@ static void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>  }
>
>  /* Define DDA registers for requested video mode. */
> -static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
> +Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>                                  R128PLLPtr pll, R128InfoPtr info,
>                                   DisplayModePtr mode)
>  {
> @@ -4026,7 +3512,7 @@ static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
>  }
>
>  /* Define DDA2 registers for requested video mode. */
> -static Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
> +Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
>                                  R128PLLPtr pll, R128InfoPtr info,
>                                   DisplayModePtr mode)
>  {
> @@ -4106,122 +3592,6 @@ static void R128InitPalette(R128SavePtr save)
>  }
>  #endif
>
> -/* Define registers for a requested video mode. */
> -static Bool R128Init(ScrnInfoPtr pScrn, DisplayModePtr mode, R128SavePtr save)
> -{
> -    R128InfoPtr info      = R128PTR(pScrn);
> -    double      dot_clock = mode->Clock/1000.0;
> -
> -#if R128_DEBUG
> -    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
> -          mode->name,
> -          dot_clock,
> -
> -          mode->HDisplay,
> -          mode->HSyncStart,
> -          mode->HSyncEnd,
> -          mode->HTotal,
> -
> -          mode->VDisplay,
> -          mode->VSyncStart,
> -          mode->VSyncEnd,
> -          mode->VTotal,
> -          pScrn->depth,
> -          pScrn->bitsPerPixel);
> -    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
> -    if (mode->Flags & V_CSYNC)     ErrorF(" C");
> -    if (mode->Flags & V_INTERLACE) ErrorF(" I");
> -    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
> -    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
> -    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
> -    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
> -    ErrorF("\n");
> -    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
> -          mode->name,
> -          dot_clock,
> -
> -          mode->CrtcHDisplay,
> -          mode->CrtcHSyncStart,
> -          mode->CrtcHSyncEnd,
> -          mode->CrtcHTotal,
> -
> -          mode->CrtcVDisplay,
> -          mode->CrtcVSyncStart,
> -          mode->CrtcVSyncEnd,
> -          mode->CrtcVTotal,
> -          pScrn->depth,
> -          pScrn->bitsPerPixel);
> -    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
> -    if (mode->Flags & V_CSYNC)     ErrorF(" C");
> -    if (mode->Flags & V_INTERLACE) ErrorF(" I");
> -    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
> -    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
> -    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
> -    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
> -    ErrorF("\n");
> -#endif
> -
> -    info->Flags = mode->Flags;
> -
> -    if(info->IsSecondary)
> -    {
> -        if (!R128InitCrtc2Registers(pScrn, save,
> -             pScrn->currentMode,info))
> -            return FALSE;
> -        R128InitPLL2Registers(pScrn, save, &info->pll, dot_clock);
> -        if (!R128InitDDA2Registers(pScrn, save, &info->pll, info, mode))
> -           return FALSE;
> -    }
> -    else
> -    {
> -        R128InitCommonRegisters(save, info);
> -        if(!R128InitCrtcRegisters(pScrn, save, mode, info))
> -            return FALSE;
> -        if(dot_clock)
> -        {
> -            R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
> -            if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
> -               return FALSE;
> -        }
> -        else
> -        {
> -            save->ppll_ref_div         = info->SavedReg.ppll_ref_div;
> -            save->ppll_div_3           = info->SavedReg.ppll_div_3;
> -            save->htotal_cntl          = info->SavedReg.htotal_cntl;
> -            save->dda_config           = info->SavedReg.dda_config;
> -            save->dda_on_off           = info->SavedReg.dda_on_off;
> -        }
> -        /* not used for now */
> -        /*if (!info->PaletteSavedOnVT) RADEONInitPalette(save);*/
> -    }
> -
> -    if (((info->DisplayType == MT_DFP) ||
> -        (info->DisplayType == MT_LCD)))
> -    {
> -        R128InitFPRegisters(&info->SavedReg, save, mode, info);
> -    }
> -
> -    R128TRACE(("R128Init returns %p\n", save));
> -    return TRUE;
> -}
> -
> -/* Initialize a new mode. */
> -static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
> -{
> -    R128InfoPtr info      = R128PTR(pScrn);
> -
> -    if (!R128Init(pScrn, mode, &info->ModeReg)) return FALSE;
> -                               /* FIXME?  DRILock/DRIUnlock here? */
> -    pScrn->vtSema = TRUE;
> -    R128Blank(pScrn);
> -    R128RestoreMode(pScrn, &info->ModeReg);
> -    R128Unblank(pScrn);
> -
> -    info->CurrentLayout.mode = mode;
> -
> -    return TRUE;
> -}
> -
>  static Bool R128SaveScreen(ScreenPtr pScreen, int mode)
>  {
>      ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
> @@ -4252,7 +3622,7 @@ Bool R128SwitchMode(SWITCH_MODE_ARGS_DECL)
>      Bool ret;
>
>      info->SwitchingMode = TRUE;
> -    ret = R128ModeInit(pScrn, mode);
> +    ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
>      info->SwitchingMode = FALSE;
>      return ret;
>  }
> @@ -4379,10 +3749,16 @@ Bool R128EnterVT(VT_FUNC_ARGS_DECL)
>      R128InfoPtr info  = R128PTR(pScrn);
>
>      R128TRACE(("R128EnterVT\n"));
> +
> +    pScrn->vtSema = TRUE;
>      if (info->FBDev) {
>          if (!fbdevHWEnterVT(VT_FUNC_ARGS)) return FALSE;
> -    } else
> -        if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
> +    } else {
> +        if (!xf86SetDesiredModes(pScrn)) return FALSE;
> +    }
> +
> +    //if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
> +
>      if (info->accelOn)
>         R128EngineInit(pScrn);
>
> @@ -4399,7 +3775,7 @@ Bool R128EnterVT(VT_FUNC_ARGS_DECL)
>  #endif
>
>      info->PaletteSavedOnVT = FALSE;
> -    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
> +    //pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
>
>      return TRUE;
>  }
> @@ -4504,130 +3880,3 @@ void R128FreeScreen(FREE_SCREEN_ARGS_DECL)
>  #endif
>      R128FreeRec(pScrn);
>  }
> -
> -/* Sets VESA Display Power Management Signaling (DPMS) Mode.  */
> -static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
> -                                         int PowerManagementMode, int flags)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -    int           mask      = (R128_CRTC_DISPLAY_DIS
> -                              | R128_CRTC_HSYNC_DIS
> -                              | R128_CRTC_VSYNC_DIS);
> -    int             mask2     = R128_CRTC2_DISP_DIS;
> -
> -    switch (PowerManagementMode) {
> -    case DPMSModeOn:
> -       /* Screen: On; HSync: On, VSync: On */
> -       if (info->IsSecondary)
> -               OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask2);
> -       else
> -               OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
> -       break;
> -    case DPMSModeStandby:
> -       /* Screen: Off; HSync: Off, VSync: On */
> -       if (info->IsSecondary)
> -               OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
> -           else
> -               OUTREGP(R128_CRTC_EXT_CNTL,
> -                       R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
> -       break;
> -    case DPMSModeSuspend:
> -       /* Screen: Off; HSync: On, VSync: Off */
> -       if (info->IsSecondary)
> -               OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
> -       else
> -               OUTREGP(R128_CRTC_EXT_CNTL,
> -                       R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
> -       break;
> -    case DPMSModeOff:
> -       /* Screen: Off; HSync: Off, VSync: Off */
> -       if (info->IsSecondary)
> -               OUTREGP(R128_CRTC2_GEN_CNTL, mask2, ~mask2);
> -       else
> -               OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
> -       break;
> -    }
> -    if(info->isDFP) {
> -       switch (PowerManagementMode) {
> -       case DPMSModeOn:
> -           OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) | (R128_FP_FPON | R128_FP_TDMS_EN));
> -           break;
> -       case DPMSModeStandby:
> -       case DPMSModeSuspend:
> -       case DPMSModeOff:
> -           OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) & ~(R128_FP_FPON | R128_FP_TDMS_EN));
> -           break;
> -       }
> -    }
> -}
> -
> -static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on);
> -
> -static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
> -                                         int PowerManagementMode, int flags)
> -{
> -    R128InfoPtr   info      = R128PTR(pScrn);
> -    unsigned char *R128MMIO = info->MMIO;
> -    int           mask      = R128_LVDS_DISPLAY_DIS;
> -
> -    switch (PowerManagementMode) {
> -    case DPMSModeOn:
> -       /* Screen: On; HSync: On, VSync: On */
> -       OUTREGP(R128_LVDS_GEN_CNTL, 0, ~mask);
> -        r128_set_backlight_enable(pScrn, 1);
> -       break;
> -    case DPMSModeStandby:
> -       /* Fall through */
> -    case DPMSModeSuspend:
> -       /* Fall through */
> -       break;
> -    case DPMSModeOff:
> -       /* Screen: Off; HSync: Off, VSync: Off */
> -       OUTREGP(R128_LVDS_GEN_CNTL, mask, ~mask);
> -        r128_set_backlight_enable(pScrn, 0);
> -       break;
> -    }
> -}
> -
> -static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on)
> -{
> -        R128InfoPtr info        = R128PTR(pScrn);
> -        unsigned char *R128MMIO = info->MMIO;
> -       unsigned int lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL);
> -
> -       lvds_gen_cntl |= (/*R128_LVDS_BL_MOD_EN |*/ R128_LVDS_BLON);
> -       if (on) {
> -               lvds_gen_cntl |= R128_LVDS_DIGON;
> -               if (!(lvds_gen_cntl & R128_LVDS_ON)) {
> -                       lvds_gen_cntl &= ~R128_LVDS_BLON;
> -                       OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
> -                       (void)INREG(R128_LVDS_GEN_CNTL);
> -                       usleep(10000);
> -                       lvds_gen_cntl |= R128_LVDS_BLON;
> -                       OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
> -               }
> -#if 0
> -               lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
> -               lvds_gen_cntl |= (0xFF /* backlight_conv[level] */ <<
> -                                 R128_LVDS_BL_MOD_LEVEL_SHIFT);
> -#endif
> -               lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_EN);
> -               lvds_gen_cntl &= ~R128_LVDS_DISPLAY_DIS;
> -       } else {
> -#if 0
> -               lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
> -               lvds_gen_cntl |= (0xFF /* backlight_conv[0] */ <<
> -                                 R128_LVDS_BL_MOD_LEVEL_SHIFT);
> -#endif
> -               lvds_gen_cntl |= R128_LVDS_DISPLAY_DIS;
> -               OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
> -               usleep(10);
> -               lvds_gen_cntl &= ~(R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON
> -                                  | R128_LVDS_DIGON);
> -       }
> -
> -       OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
> -
> -       return 0;
> -}
> diff --git a/src/r128_output.c b/src/r128_output.c
> new file mode 100644
> index 0000000..00d552f
> --- /dev/null
> +++ b/src/r128_output.c
> @@ -0,0 +1,465 @@
> +/*
> + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
> + *                VA Linux Systems Inc., Fremont, California.
> + *
> + * All Rights Reserved.
> + *
> + * 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 on 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
> + * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
> + * THEIR SUPPLIERS 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 <string.h>
> +#include <stdio.h>
> +
> +#include "xf86.h"
> +#include "xf86Modes.h"
> +
> +#include "r128.h"
> +#include "r128_probe.h"
> +#include "r128_reg.h"
> +
> +static void R128ConnectorFindMonitor(ScrnInfoPtr pScrn, xf86OutputPtr output);
> +
> +static void r128_dpms(xf86OutputPtr output, int mode)
> +{
> +    switch(mode) {
> +    case DPMSModeOn:
> +        R128DPMSSetOn(output);
> +        break;
> +    case DPMSModeStandby:
> +    case DPMSModeSuspend:
> +    case DPMSModeOff:
> +        R128DPMSSetOff(output);
> +        break;
> +    }
> +}
> +
> +static void r128_save(xf86OutputPtr output)
> +{
> +}
> +
> +static void r128_restore(xf86OutputPtr output)
> +{
> +}
> +
> +static int r128_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
> +{
> +    return MODE_OK;
> +}
> +
> +static Bool r128_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
> +{
> +    return TRUE;
> +}
> +
> +static void r128_mode_prepare(xf86OutputPtr output)
> +{
> +    r128_dpms(output, DPMSModeOff);
> +}
> +
> +static void r128_mode_set(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
> +{
> +}
> +
> +static void r128_mode_commit(xf86OutputPtr output)
> +{
> +    r128_dpms(output, DPMSModeOn);
> +}
> +
> +static xf86OutputStatus r128_detect(xf86OutputPtr output)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +
> +    r128_output->MonType = MT_UNKNOWN;
> +    R128ConnectorFindMonitor(pScrn, output);
> +
> +    if (r128_output->MonType == MT_UNKNOWN) {
> +        output->subpixel_order = SubPixelUnknown;
> +        return XF86OutputStatusUnknown;
> +    } else if (r128_output->MonType == MT_NONE) {
> +        output->subpixel_order = SubPixelUnknown;
> +        return XF86OutputStatusDisconnected;
> +    } else {
> +        switch(r128_output->MonType) {
> +        case MT_LCD:
> +        case MT_DFP:
> +            output->subpixel_order = SubPixelHorizontalRGB;
> +            break;
> +        default:
> +            output->subpixel_order = SubPixelNone;
> +            break;
> +        }
> +
> +        return XF86OutputStatusConnected;
> +    }
> +}
> +
> +static DisplayModePtr r128_get_modes(xf86OutputPtr output)
> +{
> +    DisplayModePtr modes;
> +    modes = R128ProbeOutputModes(output);
> +    return modes;
> +}
> +
> +static void r128_destroy(xf86OutputPtr output)
> +{
> +    if (output->driver_private)
> +        free(output->driver_private);
> +}
> +
> +static const xf86OutputFuncsRec r128_output_funcs = {
> +    .dpms = r128_dpms,
> +    .save = r128_save,
> +    .restore = r128_restore,
> +    .mode_valid = r128_mode_valid,
> +    .mode_fixup = r128_mode_fixup,
> +    .prepare = r128_mode_prepare,
> +    .mode_set = r128_mode_set,
> +    .commit = r128_mode_commit,
> +    .detect = r128_detect,
> +    .get_modes = r128_get_modes,
> +    .destroy = r128_destroy,
> +};
> +
> +void R128DPMSSetOn(xf86OutputPtr output)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +    R128MonitorType MonType = r128_output->MonType;
> +
> +    switch(MonType) {
> +    case MT_LCD:
> +        OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_BLON, ~R128_LVDS_BLON);
> +        usleep(info->PanelPwrDly * 1000);
> +        OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_ON, ~R128_LVDS_ON);
> +        break;
> +    case MT_DFP:
> +        OUTREGP(R128_FP_GEN_CNTL, (R128_FP_FPON | R128_FP_TDMS_EN), ~(R128_FP_FPON | R128_FP_TDMS_EN));
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +void R128DPMSSetOff(xf86OutputPtr output)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +    R128MonitorType MonType = r128_output->MonType;
> +
> +    switch(MonType) {
> +    case MT_LCD:
> +        OUTREGP(R128_LVDS_GEN_CNTL, 0, ~(R128_LVDS_BLON | R128_LVDS_ON));
> +        break;
> +    case MT_DFP:
> +        OUTREGP(R128_FP_GEN_CNTL, 0, ~(R128_FP_FPON | R128_FP_TDMS_EN));
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static R128MonitorType R128DisplayDDCConnected(xf86OutputPtr output)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128InfoPtr info = R128PTR(pScrn);
> +    unsigned char *R128MMIO = info->MMIO;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +
> +    R128MonitorType MonType = MT_NONE;
> +    xf86MonPtr *MonInfo = &output->MonInfo;
> +    CARD32 mask1, mask2;
> +
> +    if (r128_output->type == OUTPUT_LVDS) {
> +        return MT_LCD;
> +    } else if (r128_output->type == OUTPUT_VGA) {
> +        mask1 = R128_GPIO_MONID_MASK_1 | R128_GPIO_MONID_MASK_3;
> +        mask2 = R128_GPIO_MONID_A_1    | R128_GPIO_MONID_A_3;
> +    } else {
> +        mask1 = R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3;
> +        mask2 = R128_GPIO_MONID_A_0    | R128_GPIO_MONID_A_3;
> +    }
> +
> +    if (r128_output->pI2CBus) {
> +        R128I2CBusPtr pR128I2CBus = &(r128_output->ddc_i2c);
> +
> +       /* XXX: Radeon does something here to appease old monitors. */
> +       OUTREG(pR128I2CBus->ddc_reg, INREG(pR128I2CBus->ddc_reg)  |  mask1);
> +       OUTREG(pR128I2CBus->ddc_reg, INREG(pR128I2CBus->ddc_reg)  & ~mask2);
> +       *MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), r128_output->pI2CBus);
> +    } else {
> +        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n");
> +        return MT_NONE;
> +    }
> +
> +    if (*MonInfo) {
> +        if (r128_output->type == OUTPUT_VGA) {
> +            MonType = MT_CRT;
> +        } else {
> +            if ((*MonInfo)->rawData[0x14] & 0x80)
> +                MonType = MT_DFP;
> +            else
> +                MonType = MT_CRT;
> +       }
> +    }
> +
> +    return MonType;
> +}
> +
> +static void R128ConnectorFindMonitor(ScrnInfoPtr pScrn, xf86OutputPtr output)
> +{
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +
> +    /* XXX: We should figure out how the DAC and BIOS scratch registers work
> +     * to handle the non-DDC case. */
> +    if (r128_output->MonType == MT_UNKNOWN)
> +        r128_output->MonType = R128DisplayDDCConnected(output);
> +}
> +
> +DisplayModePtr R128ProbeOutputModes(xf86OutputPtr output)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +    DisplayModePtr modes = NULL;
> +    DisplayModePtr mode;
> +    xf86MonPtr edid_mon;
> +
> +    if (r128_output->pI2CBus) {
> +        edid_mon = xf86OutputGetEDID(output, r128_output->pI2CBus);
> +        xf86OutputSetEDID(output, edid_mon);
> +        modes = xf86OutputGetEDIDModes(output);
> +    }
> +
> +    /* Letting this function return NULL would be a bad idea. With old cards
> +     * like r128, users often specify a small resolution in order to get DRI.
> +     * If the X server has to guess modes, the list it comes up with includes
> +     * high resolutions.
> +     */
> +    if (!modes)
> +        modes = xf86GetDefaultModes();
> +
> +    for (mode = modes; mode != NULL; mode = mode->next) {
> +       xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
> +       if (mode->status == MODE_OK)
> +            mode->status = R128ValidMode(XF86_SCRN_ARG(pScrn), mode, TRUE, MODECHECK_FINAL);
> +    }
> +
> +    xf86ValidateModesUserConfig(pScrn, modes);
> +    xf86PruneInvalidModes(pScrn, &modes, FALSE);
> +
> +    return modes;
> +}
> +
> +static xf86OutputPtr R128OutputCreate(ScrnInfoPtr pScrn, const char *name, int i)
> +{
> +    char buf[32];
> +    sprintf(buf, name, i);
> +    return xf86OutputCreate(pScrn, &r128_output_funcs, buf);
> +}
> +
> +static void R128I2CGetBits(I2CBusPtr b, int *Clock, int *data)
> +{
> +    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
> +    R128InfoPtr   info        = R128PTR(pScrn);
> +    unsigned long val;
> +    unsigned char *R128MMIO   = info->MMIO;
> +    R128I2CBusPtr pR128I2CBus = b->DriverPrivate.ptr;
> +
> +    /* Get the result. */
> +    val = INREG(pR128I2CBus->ddc_reg);
> +    *Clock = (val & pR128I2CBus->get_clk_mask)  != 0;
> +    *data  = (val & pR128I2CBus->get_data_mask) != 0;
> +}
> +
> +static void R128I2CPutBits(I2CBusPtr b, int Clock, int data)
> +{
> +    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
> +    R128InfoPtr   info        = R128PTR(pScrn);
> +    unsigned long val;
> +    unsigned char *R128MMIO   = info->MMIO;
> +    R128I2CBusPtr pR128I2CBus = b->DriverPrivate.ptr;
> +
> +    val = INREG(pR128I2CBus->ddc_reg)
> +              & ~(CARD32)(pR128I2CBus->put_clk_mask | pR128I2CBus->put_data_mask);
> +    val |= (Clock ? 0 : pR128I2CBus->put_clk_mask);
> +    val |= (data  ? 0 : pR128I2CBus->put_data_mask);
> +    OUTREG(pR128I2CBus->ddc_reg, val);
> +}
> +
> +static Bool R128I2CInit(xf86OutputPtr output, I2CBusPtr *bus_ptr, char *name)
> +{
> +    ScrnInfoPtr pScrn = output->scrn;
> +    R128OutputPrivatePtr r128_output = output->driver_private;
> +    R128I2CBusPtr pR128I2CBus = &(r128_output->ddc_i2c);
> +    I2CBusPtr pI2CBus;
> +
> +    pI2CBus = xf86CreateI2CBusRec();
> +    if(!pI2CBus) return FALSE;
> +
> +    pI2CBus->BusName     = name;
> +    pI2CBus->scrnIndex   = pScrn->scrnIndex;
> +    pI2CBus->I2CPutBits  = R128I2CPutBits;
> +    pI2CBus->I2CGetBits  = R128I2CGetBits;
> +    pI2CBus->AcknTimeout = 5;
> +
> +    pI2CBus->DriverPrivate.ptr = (pointer)pR128I2CBus;
> +    if (!xf86I2CBusInit(pI2CBus)) return FALSE;
> +
> +    *bus_ptr = pI2CBus;
> +    return TRUE;
> +}
> +
> +void R128SetOutputType(ScrnInfoPtr pScrn, R128OutputPrivatePtr r128_output)
> +{
> +    R128OutputType output = OUTPUT_NONE;
> +
> +    switch (r128_output->ConnectorType) {
> +    case CONNECTOR_VGA:
> +        output = OUTPUT_VGA;
> +        break;
> +    case CONNECTOR_LVDS:
> +        output = OUTPUT_LVDS;
> +        break;
> +    case CONNECTOR_DVI_D:
> +    case CONNECTOR_DVI_I:
> +    case CONNECTOR_DVI_A:
> +        output = OUTPUT_DVI;
> +        break;
> +    default:
> +        output = OUTPUT_NONE;
> +    }
> +
> +    r128_output->type = output;
> +}
> +
> +void R128SetupGenericConnectors(ScrnInfoPtr pScrn)
> +{
> +    R128InfoPtr info = R128PTR(pScrn);
> +
> +    if (!info->HasCRTC2 && !info->isDFP) {
> +        info->BiosConnector[0].ConnectorType = CONNECTOR_VGA;
> +        info->BiosConnector[0].valid = TRUE;
> +        return;
> +    } else if (!info->HasCRTC2) {
> +        info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_D;
> +       info->BiosConnector[0].valid = TRUE;
> +       return;
> +    }
> +
> +    info->BiosConnector[0].ConnectorType = CONNECTOR_LVDS;
> +    info->BiosConnector[0].valid = TRUE;
> +
> +    info->BiosConnector[1].ConnectorType = CONNECTOR_VGA;
> +    info->BiosConnector[1].valid = TRUE;
> +}
> +
> +Bool R128SetupConnectors(ScrnInfoPtr pScrn)
> +{
> +    R128InfoPtr info = R128PTR(pScrn);
> +    xf86OutputPtr output;
> +    int num_vga = 0;
> +    int num_dvi = 0;
> +    int i;
> +
> +    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
> +        info->BiosConnector[i].valid = FALSE;
> +        info->BiosConnector[i].ConnectorType = CONNECTOR_NONE;
> +    }
> +
> +    /* XXX: Can we make R128GetConnectorInfoFromBIOS()? */
> +    R128SetupGenericConnectors(pScrn);
> +
> +    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
> +        if (info->BiosConnector[i].valid) {
> +            if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) ||
> +                (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I) ||
> +                (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
> +                num_dvi++;
> +            } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA) {
> +                num_vga++;
> +            }
> +        }
> +    }
> +
> +    for (i = 0; i < R128_MAX_BIOS_CONNECTOR; i++) {
> +        if (info->BiosConnector[i].valid) {
> +           R128I2CBusRec i2c;
> +            R128OutputPrivatePtr r128_output;
> +            R128ConnectorType conntype = info->BiosConnector[i].ConnectorType;
> +
> +            if (conntype == CONNECTOR_NONE)
> +                continue;
> +
> +            r128_output = xnfcalloc(sizeof(R128OutputPrivateRec), 1);
> +            if (!r128_output) return FALSE;
> +
> +            r128_output->MonType = MT_UNKNOWN;
> +            r128_output->ConnectorType = conntype;
> +            r128_output->num = i;
> +
> +            if (conntype == CONNECTOR_LVDS) {
> +                output = R128OutputCreate(pScrn, "LVDS", 0);
> +            } else if (conntype == CONNECTOR_VGA) {
> +                output = R128OutputCreate(pScrn, "VGA-%d", --num_vga);
> +            } else {
> +                output = R128OutputCreate(pScrn, "DVI-%d", --num_dvi);
> +            }
> +
> +            if (!output) return FALSE;
> +            output->interlaceAllowed = TRUE;
> +            output->doubleScanAllowed = TRUE;
> +            output->driver_private = r128_output;
> +           output->possible_clones = 0;
> +           if (conntype == CONNECTOR_LVDS || !info->HasCRTC2)
> +               output->possible_crtcs = 1;
> +           else
> +               output->possible_crtcs = 2;
> +
> +            if (conntype != CONNECTOR_LVDS && info->DDC) {
> +               i2c.ddc_reg      = R128_GPIO_MONID;
> +               i2c.put_clk_mask = R128_GPIO_MONID_EN_3;
> +               i2c.get_clk_mask = R128_GPIO_MONID_Y_3;
> +               if (conntype == CONNECTOR_VGA) {
> +                   i2c.put_data_mask = R128_GPIO_MONID_EN_1;
> +                   i2c.get_data_mask = R128_GPIO_MONID_Y_1;
> +               } else {
> +                   i2c.put_data_mask = R128_GPIO_MONID_EN_0;
> +                   i2c.get_data_mask = R128_GPIO_MONID_Y_0;
> +               }
> +               r128_output->ddc_i2c = i2c;
> +               R128I2CInit(output, &r128_output->pI2CBus, output->name);
> +           }
> +
> +            R128SetOutputType(pScrn, r128_output);
> +        }
> +    }
> +
> +    return TRUE;
> +}
> diff --git a/src/r128_probe.c b/src/r128_probe.c
> index 12e0c1c..e623bc9 100644
> --- a/src/r128_probe.c
> +++ b/src/r128_probe.c
> @@ -48,7 +48,6 @@
>  #include "xf86Resources.h"
>  #endif
>
> -#include "compat-api.h"
>  #include "r128_probe.h"
>
>  #ifndef XSERVER_LIBPCIACCESS
> diff --git a/src/r128_probe.h b/src/r128_probe.h
> index 7b55e71..f521a13 100644
> --- a/src/r128_probe.h
> +++ b/src/r128_probe.h
> @@ -37,6 +37,15 @@
>  #define _R128_PROBE_H_ 1
>
>  #include "xf86str.h"
> +#include "xf86DDC.h"
> +#include "randrstr.h"
> +#include "xf86Crtc.h"
> +
> +#include "compat-api.h"
> +
> +#ifdef USE_EXA
> +#include "exa.h"
> +#endif
>
>  /* Chip definitions */
>  #define PCI_VENDOR_ATI                 0x1002
> @@ -90,6 +99,73 @@
>
>  extern DriverRec R128;
>
> +typedef enum
> +{
> +    MT_UNKNOWN = -1,
> +    MT_NONE    = 0,
> +    MT_CRT     = 1,
> +    MT_LCD     = 2,
> +    MT_DFP     = 3,
> +    MT_CTV     = 4,
> +    MT_STV     = 5
> +} R128MonitorType;
> +
> +typedef enum
> +{
> +    CONNECTOR_NONE,
> +    CONNECTOR_VGA,
> +    CONNECTOR_DVI_I,
> +    CONNECTOR_DVI_D,
> +    CONNECTOR_DVI_A,
> +    CONNECTOR_LVDS
> +} R128ConnectorType;
> +
> +typedef enum
> +{
> +    OUTPUT_NONE,
> +    OUTPUT_VGA,
> +    OUTPUT_DVI,
> +    OUTPUT_LVDS
> +} R128OutputType;
> +
> +typedef struct {
> +    CARD32 ddc_reg;
> +    CARD32 put_clk_mask;
> +    CARD32 put_data_mask;
> +    CARD32 get_clk_mask;
> +    CARD32 get_data_mask;
> +} R128I2CBusRec, *R128I2CBusPtr;
> +
> +typedef struct _R128CrtcPrivateRec {
> +#ifdef HAVE_XAA_H
> +    FBLinearPtr rotate_mem_xaa;
> +#endif
> +#ifdef USE_EXA
> +    ExaOffscreenArea *rotate_mem_exa;
> +#endif
> +    int crtc_id;
> +    CARD32 cursor_offset;
> +    /* Lookup table values to be set when the CRTC is enabled */
> +    CARD8 lut_r[256], lut_g[256], lut_b[256];
> +} R128CrtcPrivateRec, *R128CrtcPrivatePtr;
> +
> +typedef struct {
> +    R128ConnectorType ConnectorType;
> +    Bool valid;
> +} R128BIOSConnector;
> +
> +typedef struct _R128OutputPrivateRec {
> +    int num;
> +    R128OutputType type;
> +    R128ConnectorType ConnectorType;
> +    R128MonitorType MonType;
> +    I2CBusPtr pI2CBus;
> +    R128I2CBusRec ddc_i2c;
> +} R128OutputPrivateRec, *R128OutputPrivatePtr;
> +
> +#define R128_MAX_CRTC 2
> +#define R128_MAX_BIOS_CONNECTOR 2
> +
>  typedef struct
>  {
>      Bool IsDRIEnabled;
> @@ -101,6 +177,9 @@ typedef struct
>      Bool IsSecondaryRestored;
>      Bool RestorePrimary;
>
> +    xf86CrtcPtr pCrtc[R128_MAX_CRTC];
> +    R128CrtcPrivatePtr Controller[R128_MAX_CRTC];
> +
>      ScrnInfoPtr pSecondaryScrn;
>      ScrnInfoPtr pPrimaryScrn;
>  } R128EntRec, *R128EntPtr;
> diff --git a/src/r128_video.c b/src/r128_video.c
> index dccaa42..6439a24 100644
> --- a/src/r128_video.c
> +++ b/src/r128_video.c
> @@ -226,7 +226,7 @@ R128SetupImageVideo(ScreenPtr pScreen)
>         return NULL;
>
>      adapt->type = XvWindowMask | XvInputMask | XvImageMask;
> -    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
> +    adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/;
>      adapt->name = "ATI Rage128 Video Overlay";
>      adapt->nEncodings = 1;
>      adapt->pEncodings = &DummyEncoding;
> @@ -849,6 +849,13 @@ R128PutImage(
>     int top, left, npixels, nlines;
>     BoxRec dstBox;
>     CARD32 tmp;
> +
> +   /* Currently, the video is only visible on the first monitor.
> +    * In the future we could try to make this smarter, or just implement
> +    * textured video. */
> +   xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> +   xf86CrtcPtr crtc = xf86_config->crtc[0];
> +
>  #if X_BYTE_ORDER == X_BIG_ENDIAN
>     unsigned char *R128MMIO = info->MMIO;
>     CARD32 config_cntl = INREG(R128_CONFIG_CNTL);
> @@ -893,10 +900,10 @@ R128PutImage(
>                              clipBoxes, width, height))
>         return Success;
>
> -   dstBox.x1 -= pScrn->frameX0;
> -   dstBox.x2 -= pScrn->frameX0;
> -   dstBox.y1 -= pScrn->frameY0;
> -   dstBox.y2 -= pScrn->frameY0;
> +   dstBox.x1 -= crtc->x;
> +   dstBox.x2 -= crtc->x;
> +   dstBox.y1 -= crtc->y;
> +   dstBox.y2 -= crtc->y;
>
>     switch(id) {
>     case FOURCC_YV12:
> --
> 1.9.3
>
> _______________________________________________
> xorg-driver-ati mailing list
> xorg-driver-ati at lists.x.org
> http://lists.x.org/mailman/listinfo/xorg-driver-ati


More information about the xorg-driver-ati mailing list