/*

	Copyright 2009 Roberto De Ioris <roberto@unbit.it>

 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * A copy of the General Public License is included with the source
 * distribution of this driver, as COPYING.


Special Thanks to Unbit (http://unbit.it) for letting me work on this stuff, and to
Marvell for sending me a wonderful sheevaplug (http://www.marvell.com/featured/plugcomputing.jsp) for testing
the driver on embedded systems.

---------------------

TODO:
- rotation
- better randr support


*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
#include <fcntl.h>

#include "displaylink.h"

#include "xf86_OSproc.h"

#include "mipointer.h"
#include "mibstore.h"
#include "micmap.h"
#include "colormapst.h"
#include "xf86cmap.h"

#include "fb.h"

#include "fbdevhw.h"


// prototypes (as fbdev)
static const OptionInfoRec * DisplayLinkAvailableOptions(int chipid, int busid);
static void	DisplayLinkIdentify(int flags);
static Bool	DisplayLinkProbe(DriverPtr drv, int flags);
static Bool	DisplayLinkPreInit(ScrnInfoPtr pScrn, int flags);
static Bool	DisplayLinkScreenInit(int Index, ScreenPtr pScreen, int argc,
				char **argv);
static Bool	DisplayLinkCloseScreen(int scrnIndex, ScreenPtr pScreen);

static Bool	DisplayLinkDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op,
				pointer ptr);
static Bool DisplayLinkInitRandR(ScreenPtr pScreen);

// damage handler
static void DLBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead);
static void DLWakeupHandler(pointer data, int i, pointer LastSelectMask);

/* RandR */
#ifdef RANDR_10_INTERFACE
static Bool DLRRSetConfigProc(ScreenPtr pScreen, Rotation rotation, int rate, RRScreenSizePtr pSize);
#endif /* RANDR_10_INTERFACE */
#if RANDR_12_INTERFACE
static Bool DLRRScreenSetSizeProc(ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight);
static Bool DLRRCrtcSetProc(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation rotation, int numOutputs, RROutputPtr *outputs);
static Bool DLRRCrtcSetGammaProc(ScreenPtr pScreen, RRCrtcPtr crtc);
static Bool DLRRCrtcGetGammaProc(ScreenPtr pScreen, RRCrtcPtr crtc);
static Bool DLRROutputSetPropertyProc(ScreenPtr pScreen, RROutputPtr output, Atom property, RRPropertyValuePtr value);
static Bool DLRROutputValidateModeProc(ScreenPtr pScreen, RROutputPtr output, RRModePtr mode);
static void DLRRModeDestroyProc(ScreenPtr pScreen, RRModePtr mode);
#endif /* RANDR_12_INTERFACE */
#if RANDR_13_INTERFACE
static Bool DLRROutputGetPropertyProc(ScreenPtr pScreen, RROutputPtr output, Atom property);
static Bool DLRRGetPanningProc(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, BoxPtr trackingArea, INT16 *border);
static Bool DLRRSetPanningProc(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, BoxPtr trackingArea, INT16 *border);
#endif /* RANDR_13_INTERFACE */
static Bool DLRRGetInfoProc(ScreenPtr pScreen, Rotation *rotations);
static Bool DLRRCloseScreenProc(int i, ScreenPtr pScreen);



static int pix24bpp = 0;

#define DL_VERSION	3
#define DL_NAME		"DL"
#define DL_DRIVER_NAME	"displaylink"


_X_EXPORT DriverRec DL = {
	DL_VERSION,
	DL_DRIVER_NAME,
	DisplayLinkIdentify,
	DisplayLinkProbe,
	DisplayLinkAvailableOptions,
	NULL,
	0,
	DisplayLinkDriverFunc,

};

/* Supported "chipsets" */
static SymTabRec DisplayLinkChipsets[] = {
    { 0, "displaylink" },
    {-1, NULL }
};


/* Supported options */
typedef enum {
	OPTION_FBDEV,
	OPTION_DEBUG
} DisplayLinkOpts;

static const OptionInfoRec DisplayLinkOptions[] = {
	{ OPTION_FBDEV,		"fbdev",	OPTV_STRING,	{0},	FALSE },
	{ -1,			NULL,		OPTV_NONE,	{0},	FALSE }
};

/* -------------------------------------------------------------------- */

#ifdef XFree86LOADER

MODULESETUPPROTO(DisplayLinkSetup);

static XF86ModuleVersionInfo DisplayLinkVersRec =
{
	"displaylink",
	MODULEVENDORSTRING,
	MODINFOSTRING1,
	MODINFOSTRING2,
	XORG_VERSION_CURRENT,
	PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
	ABI_CLASS_VIDEODRV,
	ABI_VIDEODRV_VERSION,
	NULL,
	{0,0,0,0}
};

_X_EXPORT XF86ModuleData displaylinkModuleData = { &DisplayLinkVersRec, DisplayLinkSetup, NULL };

pointer
DisplayLinkSetup(pointer module, pointer opts, int *errmaj, int *errmin)
{
	static Bool setupDone = FALSE;

	if (!setupDone) {
		setupDone = TRUE;
		xf86AddDriver(&DL, module, HaveDriverFuncs);
		return (pointer)1;
	} else {
		if (errmaj) *errmaj = LDR_ONCEONLY;
		return NULL;
	}
}

#endif /* XFree86LOADER */


static Bool
DisplayLinkGetRec(ScrnInfoPtr pScrn)
{
	if (pScrn->driverPrivate != NULL)
		return TRUE;
	
	pScrn->driverPrivate = xnfcalloc(sizeof(DisplayLinkRec), 1);
	return TRUE;
}

static void
DisplayLinkFreeRec(ScrnInfoPtr pScrn)
{
	if (pScrn->driverPrivate == NULL)
		return;
	xfree(pScrn->driverPrivate);
	pScrn->driverPrivate = NULL;
}

static const OptionInfoRec *
DisplayLinkAvailableOptions(int chipid, int busid)
{
	return DisplayLinkOptions;
}

static void
DisplayLinkIdentify(int flags)
{
	xf86PrintChipsets(DL_NAME, "driver for ", DisplayLinkChipsets);
}



static Bool
DisplayLinkProbe(DriverPtr drv, int flags)
{
	int i;
	ScrnInfoPtr pScrn ;
       	GDevPtr *devSections;
	int numDevSections;
	int bus,device,func;
	char *dev;
	int entity;
	Bool foundScreen = FALSE;

	if ((numDevSections = xf86MatchDevice(DL_DRIVER_NAME, &devSections)) <= 0) 
	    return FALSE;
	
	if (!xf86LoadDrvSubModule(drv, "fbdevhw"))
	    return FALSE;
	    
	for (i = 0; i < numDevSections; i++) {

	    pScrn = NULL;
	    dev = xf86FindOptionValue(devSections[i]->options,"fbdev");

	    if (fbdevHWProbe(NULL,dev,NULL)) {

		entity = xf86ClaimFbSlot(drv, 0,
                                              devSections[i], TRUE);		
		pScrn = xf86ConfigFbEntity(pScrn,0,entity,
					       NULL,NULL,NULL,NULL);
		
	    }

	    // hack for system with real cards		
	    fbSlotClaimed = FALSE;

	    if (pScrn) {
	    	foundScreen = TRUE;
	    
	    	pScrn->driverVersion = DL_VERSION;
	    	pScrn->driverName    = DL_DRIVER_NAME;
	    	pScrn->name          = DL_NAME;
	    	pScrn->Probe         = DisplayLinkProbe;
	    	pScrn->PreInit       = DisplayLinkPreInit;
	    	pScrn->ScreenInit    = DisplayLinkScreenInit;
	    	pScrn->SwitchMode    = fbdevHWSwitchModeWeak();
	    	pScrn->AdjustFrame   = fbdevHWAdjustFrameWeak();
	    	pScrn->EnterVT       = fbdevHWEnterVTWeak();
	    	pScrn->LeaveVT       = fbdevHWLeaveVTWeak();
	    	pScrn->ValidMode     = fbdevHWValidModeWeak();

	    	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
		       "using %s\n", dev ? dev : "default device");
		}
	}
	xfree(devSections);
	return foundScreen;
}


displaylink_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
{
    int         old_x = scrn->virtualX;
    int         old_y = scrn->virtualY;

    fprintf(stderr,"displaylink CRTC resize !!! %dx%d\n", width, height);

    if (old_x == width && old_y == height)
        return TRUE;

    scrn->virtualX = width;
    scrn->virtualY = height;
    return TRUE;
}

static const xf86CrtcConfigFuncsRec displaylink_xf86crtc_config_funcs = {
    displaylink_xf86crtc_resize
};

static Bool
DisplayLinkPreInit(ScrnInfoPtr pScrn, int flags)
{
	DisplayLinkPtr fPtr;
	int default_depth, fbbpp;
	const char *s;
	int type;
	char edid[128];
	xf86MonPtr DLMonPtr;

	if (flags & PROBE_DETECT) return FALSE;


	/* Check the number of entities, and fail if it isn't one. */
	if (pScrn->numEntities != 1)
		return FALSE;

	pScrn->monitor = pScrn->confScreen->monitor;

	DisplayLinkGetRec(pScrn);
	fPtr = DLPTR(pScrn);

	fPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);

	/* open device */
	if (!fbdevHWInit(pScrn,NULL,xf86FindOptionValue(fPtr->pEnt->device->options,"fbdev")))
		return FALSE;

	// Damn, better to use fbdevHWGetFD()...
        fPtr->fd = open(xf86FindOptionValue(fPtr->pEnt->device->options,"fbdev"),O_WRONLY);
	if (fPtr->fd < 0) {
		return FALSE;
	}

	ioctl(fPtr->fd,DL_IOCTL_EDID, edid);
	DLMonPtr = xf86InterpretEDID(pScrn->scrnIndex, (Uchar *) edid);
	xf86PrintEDID(DLMonPtr);


	default_depth = fbdevHWGetDepth(pScrn,&fbbpp);
	if (!xf86SetDepthBpp(pScrn, default_depth, default_depth, fbbpp,
			     Support24bppFb | Support32bppFb | SupportConvert32to24 | SupportConvert24to32))
		return FALSE;
	xf86PrintDepthBpp(pScrn);

	/* Get the depth24 pixmap format */
	if (pScrn->depth == 24 && pix24bpp == 0)
		pix24bpp = xf86GetBppFromDepth(pScrn, 24);

	/* color weight */
	if (pScrn->depth > 8) {
		rgb zeros = { 0, 0, 0 };
		if (!xf86SetWeight(pScrn, zeros, zeros))
			return FALSE;
	}

	/* visual init */
	if (!xf86SetDefaultVisual(pScrn, -1))
		return FALSE;

	/* We don't currently support DirectColor at > 8bpp */
	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "requested default visual"
			   " (%s) is not supported at depth %d\n",
			   xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
		return FALSE;
	}

	{
		Gamma zeros = {0.0, 0.0, 0.0};

		if (!xf86SetGamma(pScrn,zeros)) {
			return FALSE;
		}
	}

	pScrn->progClock = TRUE;
	pScrn->rgbBits   = 8;
	pScrn->chipset   = "displaylink";
	pScrn->videoRam  = fbdevHWGetVidmem(pScrn);

	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hardware: %s (video memory:"
		   " %dkB)\n", fbdevHWGetName(pScrn), pScrn->videoRam/1024);

	/* handle options */
	xf86CollectOptions(pScrn, NULL);
	if (!(fPtr->Options = xalloc(sizeof(DisplayLinkOptions))))
		return FALSE;
	memcpy(fPtr->Options, DisplayLinkOptions, sizeof(DisplayLinkOptions));
	xf86ProcessOptions(pScrn->scrnIndex, fPtr->pEnt->device->options, fPtr->Options);


	/* Load fb module */
	if (xf86LoadSubModule(pScrn, "fb") == NULL) {
		DisplayLinkFreeRec(pScrn);
		return FALSE;
	}


	xf86CrtcConfigInit(pScrn, &displaylink_xf86crtc_config_funcs);

	dl_crtc_init(pScrn);
        if (!fPtr->crtc) {
		DisplayLinkFreeRec(pScrn);
        	return FALSE;
	}

        displaylink_output_init(pScrn);

	if (!fPtr->output) {
		DisplayLinkFreeRec(pScrn);
        	return FALSE;
	}

	/* setup video modes */

	/* check for edid incongruences (as when udlfb is loaded before attaching a monitor) */
	pScrn->currentMode = fbdevHWGetBuildinMode(pScrn) ;
	
	pScrn->modes = fPtr->output->funcs->get_modes(fPtr->output);
	if (pScrn->modes->HDisplay <= pScrn->currentMode->HDisplay && pScrn->modes->VDisplay <= pScrn->currentMode->VDisplay) {
		pScrn->currentMode = pScrn->modes ;
	}
	pScrn->virtualX = pScrn->currentMode->HDisplay ;
	pScrn->virtualY = pScrn->currentMode->VDisplay ;

	xf86CrtcSetSizeRange (pScrn, 320, 200, pScrn->virtualX, pScrn->virtualY);

	xf86InitialConfiguration (pScrn, TRUE);

	xf86PrintModes(pScrn);

	pScrn->displayWidth = pScrn->virtualX;

	xf86SetDpi(pScrn, 0, 0);


	return TRUE;
}


static Bool
DisplayLinkCreateScreenResources(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    DisplayLinkPtr fPtr = DLPTR(pScrn);
    Bool ret;

    pScreen->CreateScreenResources = fPtr->CreateScreenResources;
    ret = pScreen->CreateScreenResources(pScreen);
    pScreen->CreateScreenResources = DisplayLinkCreateScreenResources;


    if (!DamageSetup(pScreen))
        return FALSE;


    fPtr->pDamage = DamageCreate((DamageReportFunc)NULL,
                                 (DamageDestroyFunc)NULL,
                                 DamageReportNone,
                                 TRUE, pScreen, pScreen);

    if (!RegisterBlockAndWakeupHandlers(DLBlockHandler, DLWakeupHandler,
                                        (pointer)pScreen))
						return FALSE;

    fPtr->pPixmap = pScreen->GetScreenPixmap(pScreen);

    DamageRegister(&fPtr->pPixmap->drawable, fPtr->pDamage);


    return TRUE;
}

static Bool
DisplayLinkDamageInit(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    DisplayLinkPtr fPtr = DLPTR(pScrn);
    

    fPtr->CreateScreenResources = pScreen->CreateScreenResources;
    pScreen->CreateScreenResources = DisplayLinkCreateScreenResources;

    return TRUE;
}


static Bool
DisplayLinkScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	DisplayLinkPtr fPtr = DLPTR(pScrn);
	VisualPtr visual;
	int init_picture = 0;
	int ret, flags;
	int type;


	if (NULL == (fPtr->fbmem = fbdevHWMapVidmem(pScrn))) {
	        xf86DrvMsg(scrnIndex,X_ERROR,"mapping of video memory"
			   " failed\n");
		return FALSE;
	}
	fPtr->fboff = fbdevHWLinearOffset(pScrn);

	fbdevHWSave(pScrn);
	fbdevHWModeInit(pScrn, pScrn->currentMode);
	fbdevHWSaveScreen(pScreen, SCREEN_SAVER_ON);
	fbdevHWAdjustFrame(scrnIndex,0,0,0);

	miClearVisualTypes();
	if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, TrueColor)) {
		xf86DrvMsg(scrnIndex,X_ERROR,"visual type setup failed"
			   " for %d bits per pixel [1]\n",
			   pScrn->bitsPerPixel);
		return FALSE;
	}

	if (!miSetPixmapDepths()) {
	  xf86DrvMsg(scrnIndex,X_ERROR,"pixmap depth setup failed\n");
	  return FALSE;
	}

	fPtr->fbstart = fPtr->fbmem + fPtr->fboff;

	ret = fbScreenInit(pScreen, fPtr->fbstart,
					   pScrn->virtualX,
					   pScrn->virtualY, pScrn->xDpi,
					   pScrn->yDpi, pScrn->displayWidth,
					   pScrn->bitsPerPixel);
	if (!ret)
		return FALSE;

	if (pScrn->bitsPerPixel > 8) {
		/* Fixup RGB ordering */
		visual = pScreen->visuals + pScreen->numVisuals;
		while (--visual >= pScreen->visuals) {
			if ((visual->class | DynamicClass) == DirectColor) {
				visual->offsetRed   = pScrn->offset.red;
				visual->offsetGreen = pScrn->offset.green;
				visual->offsetBlue  = pScrn->offset.blue;
				visual->redMask     = pScrn->mask.red;
				visual->greenMask   = pScrn->mask.green;
				visual->blueMask    = pScrn->mask.blue;
			}
		}
	}

	/* must be after RGB ordering fixed */
	if (!fbPictureInit(pScreen, NULL, 0))
		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
			   "Render extension initialisation failed\n");

	if (!DisplayLinkDamageInit(pScreen)) {
	    xf86DrvMsg(scrnIndex, X_ERROR,
		       "damage initialization failed\n");
	    return FALSE;
	}


	xf86SetBlackWhitePixels(pScreen);
	miInitializeBackingStore(pScreen);
	xf86SetBackingStore(pScreen);

	/* software cursor */
	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());

	/* colormap */
	if (!miCreateDefColormap(pScreen)) {
			xf86DrvMsg(scrnIndex, X_ERROR,
                                   "internal error: miCreateDefColormap failed "
				   "in DisplayLinkScreenInit()\n");
		return FALSE;
	}

	flags = CMAP_PALETTED_TRUECOLOR;
	if(!xf86HandleColormaps(pScreen, 256, 8, fbdevHWLoadPaletteWeak(), 
				NULL, flags))
		return FALSE;

	xf86DPMSInit(pScreen, fbdevHWDPMSSetWeak(), 0);

	xf86CrtcScreenInit (pScreen);

	pScreen->SaveScreen = fbdevHWSaveScreenWeak();

	/* Should probably do this earlier in case it fails */
	if (!DisplayLinkInitRandR(pScreen))
		return FALSE;

	/* Wrap the current CloseScreen function */
	fPtr->CloseScreen = pScreen->CloseScreen;
	pScreen->CloseScreen = DisplayLinkCloseScreen;

	if (serverGeneration == 1)
		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);

	return TRUE;
}

static Bool
DisplayLinkCloseScreen(int scrnIndex, ScreenPtr pScreen)
{
	ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
	DisplayLinkPtr fPtr = DLPTR(pScrn);
	
	DamageUnregister(&fPtr->pPixmap->drawable, fPtr->pDamage);
	RemoveBlockAndWakeupHandlers(DLBlockHandler, DLWakeupHandler,
                                 (pointer) pScreen);
	fbdevHWRestore(pScrn);
	fbdevHWUnmapVidmem(pScrn);
	//close(fPtr->fd);
	pScrn->vtSema = FALSE;

	pScreen->CreateScreenResources = fPtr->CreateScreenResources;
	pScreen->CloseScreen = fPtr->CloseScreen;
	return (*pScreen->CloseScreen)(scrnIndex, pScreen);
}




static Bool
DisplayLinkDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
{
    xorgHWFlags *flag;
    
    switch (op) {
	case GET_REQUIRED_HW_INTERFACES:
	    flag = (CARD32*)ptr;
	    (*flag) = 0;
	    return TRUE;
	default:
	    return FALSE;
    }
}


// real drawing function

static void
DLBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
{
    ScreenPtr pScreen = (ScreenPtr) data;
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
        DisplayLinkPtr fPtr = DLPTR(pScrn);
	RegionPtr pRegion;
	int coords[4];

	if (!fPtr->pDamage)
		return;

	pRegion = DamageRegion(fPtr->pDamage);
        if (REGION_NOTEMPTY(pScreen, pRegion)) {
		int         nbox = REGION_NUM_RECTS (pRegion);
        	BoxPtr      pbox = REGION_RECTS (pRegion);

		coords[0] = pScrn->virtualX ;
        	coords[1] = pScrn->virtualY ;
        	coords[2] = 0 ;
        	coords[3] = 0 ;

		while(nbox--) {
                	if (pbox->x1 < coords[0])
                        	coords[0] = pbox->x1 ;

                	if (pbox->y1 < coords[1])
                        	coords[1] = pbox->y1 ;

                	if ( pbox->x2  > coords[2])
                        	coords[2] = pbox->x2 ;

                	if ( pbox->y2 > coords[3])
                        	coords[3] = pbox->y2 ;

                	pbox++;
        	}

        	coords[2] = coords[2] - coords[0] ;
        	coords[3] = coords[3] - coords[1] ;

        	ioctl(fPtr->fd, DL_IOCTL_BLIT, &coords);

        	DamageEmpty(fPtr->pDamage);
    	}


}

static void
DLWakeupHandler(pointer data, int i, pointer LastSelectMask)
{
}

static Bool
DisplayLinkInitRandR(ScreenPtr pScreen)
{
	rrScrPrivPtr pScrPriv;
	RRScreenSizePtr pScrSz;
	ScrnInfoPtr pScrn;
	DisplayLinkPtr pDLPtr;

    xRRModeInfo modeInfo;
    char name[64];

	int rotations = RR_Rotate_0;

	if (pScreen == NULL)
		return FALSE;

	pScrn = xf86Screens[pScreen->myNum];
	if (pScrn == NULL)
		return FALSE;

	pDLPtr = DLPTR(pScrn);
	if (pDLPtr == NULL)
		return FALSE;

	if (!RRScreenInit(pScreen))
		return FALSE;

	pScrPriv = rrGetScrPriv(pScreen);
	if (pScrPriv == NULL)
		return FALSE;

	/* Setup function pointers */	
#if RANDR_10_INTERFACE
	pScrPriv->rrSetConfig = DLRRSetConfigProc;
#endif /* RANDR_10_INTERFACE */
#if RANDR_12_INTERFACE
	pScrPriv->rrScreenSetSize = DLRRScreenSetSizeProc;
	pScrPriv->rrCrtcSet = DLRRCrtcSetProc;
	pScrPriv->rrCrtcSetGamma = DLRRCrtcSetGammaProc;
	/*pScrPriv->rrCrtcGetGamma = DLRRCrtcGetGammaProc;*/
	pScrPriv->rrOutputSetProperty = DLRROutputSetPropertyProc;
	pScrPriv->rrOutputValidateMode = DLRROutputValidateModeProc;
	pScrPriv->rrModeDestroy = DLRRModeDestroyProc;
#endif /* RANDR_12_INTERFACE */
#if RANDR_13_INTERFACE
	pScrPriv->rrOutputGetProperty = DLRROutputGetPropertyProc;
	pScrPriv->rrGetPanning = DLRRGetPanningProc;
	pScrPriv->rrSetPanning = DLRRSetPanningProc;
#endif /* RANDR_13_INTERFACE */
	pScrPriv->rrGetInfo = DLRRGetInfoProc;
	pScrPriv->CloseScreen	= DLRRCloseScreenProc;

	sprintf(name, "%dx%d", pScreen->width, pScreen->height);
    memset(&modeInfo, '\0', sizeof(modeInfo));
    modeInfo.width = pScreen->width;
    modeInfo.height = pScreen->height;
    modeInfo.nameLength = strlen(name);
    
    pDLPtr->pRRMode = RRModeGet(&modeInfo, name);
    if (!pDLPtr->pRRMode)
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RRModeGet failed!\n");
		return FALSE;
	}

	pDLPtr->pRRCrtc = RRCrtcCreate(pScreen, NULL);
	if (pDLPtr->pRRCrtc == NULL)
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RRCrtcCreate failed!\n");
		return FALSE;
	}
	
	pDLPtr->pRROutput = RROutputCreate(pScreen, pScrn->name, strlen(pScrn->name), NULL);
	if (pDLPtr->pRROutput == NULL)
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RROutputCreate failed!\n");
		return FALSE;
	}

	if (!RROutputSetClones(pDLPtr->pRROutput, NULL, 0))
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RROutputSetClones failed!\n");
		return FALSE;
	}

    if (!RROutputSetModes(pDLPtr->pRROutput, &(pDLPtr->pRRMode), 1, 0))
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RROutputSetModes failed!\n");
		return FALSE;
	}

    if (!RROutputSetCrtcs(pDLPtr->pRROutput, &(pDLPtr->pRRCrtc), 1))
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RROutputSetCrtcs failed!\n");
		return FALSE;
	}

    if (!RROutputSetConnection(pDLPtr->pRROutput, RR_Connected))
	{
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RROutputSetConnection failed!\n");
		return FALSE;
	}

    RRCrtcNotify(pDLPtr->pRRCrtc, pDLPtr->pRRMode, 0, 0, RR_Rotate_0, NULL, 1, &(pDLPtr->pRROutput));

	return TRUE;
}

#ifdef RANDR_10_INTERFACE
static Bool
DLRRSetConfigProc(ScreenPtr pScreen, Rotation rotation, int rate, RRScreenSizePtr pSize)
{
	/* What goes here? */
	return FALSE;
}
#endif /* RANDR_10_INTERFACE */

#if RANDR_12_INTERFACE
static Bool DLRRScreenSetSizeProc(ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
{
	/* What goes here? */
	return FALSE;	
}

static Bool
DLRRCrtcSetProc(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation rotation, int numOutputs, RROutputPtr *outputs)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRRCrtcSetGammaProc(ScreenPtr pScreen, RRCrtcPtr crtc)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRRCrtcGetGammaProc(ScreenPtr pScreen, RRCrtcPtr crtc)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRROutputSetPropertyProc(ScreenPtr pScreen, RROutputPtr output, Atom property, RRPropertyValuePtr value)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRROutputValidateModeProc(ScreenPtr pScreen, RROutputPtr output, RRModePtr mode)
{
	/* What goes here? */
	return FALSE;
}

static void
DLRRModeDestroyProc(ScreenPtr pScreen, RRModePtr mode)
{
	/* What goes here? */
}
#endif /* RANDR_12_INTERFACE */

#if RANDR_13_INTERFACE
static Bool
DLRROutputGetPropertyProc(ScreenPtr pScreen, RROutputPtr output, Atom property)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRRGetPanningProc(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, BoxPtr trackingArea, INT16 *border)
{
	/* What goes here? */
	return FALSE;
}

static Bool
DLRRSetPanningProc(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, BoxPtr trackingArea, INT16 *border)
{
	/* What goes here? */
	return FALSE;
}
#endif /* RANDR_13_INTERFACE */

static Bool
DLRRGetInfoProc(ScreenPtr pScreen, Rotation *rotations)
{
	/* No rotations */
	if (rotations != NULL)
		*rotations = RR_Rotate_0;

	return TRUE;
}

static Bool
DLRRCloseScreenProc(int i, ScreenPtr pScreen)
{
	/* What goes here? */
	return TRUE;
}
