xorg_driver.c revision 2ea061509ddab9054514ad87f28de950fb30dba1
1/*
2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 *
26 * Author: Alan Hourihane <alanh@tungstengraphics.com>
27 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
28 *
29 */
30
31
32#include "xorg-server.h"
33#include "xf86.h"
34#include "xf86_OSproc.h"
35#include "compiler.h"
36#include "xf86PciInfo.h"
37#include "xf86Pci.h"
38#include "mipointer.h"
39#include "micmap.h"
40#include <X11/extensions/randr.h>
41#include "fb.h"
42#include "edid.h"
43#include "xf86i2c.h"
44#include "xf86Crtc.h"
45#include "miscstruct.h"
46#include "dixstruct.h"
47#include "xf86xv.h"
48#include <X11/extensions/Xv.h>
49#ifndef XSERVER_LIBPCIACCESS
50#error "libpciaccess needed"
51#endif
52
53#include <pciaccess.h>
54
55#include "pipe/p_context.h"
56#include "xorg_tracker.h"
57#include "xorg_winsys.h"
58
59static void AdjustFrame(int scrnIndex, int x, int y, int flags);
60static Bool CloseScreen(int scrnIndex, ScreenPtr pScreen);
61static Bool EnterVT(int scrnIndex, int flags);
62static Bool SaveHWState(ScrnInfoPtr pScrn);
63static Bool RestoreHWState(ScrnInfoPtr pScrn);
64
65
66static ModeStatus ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
67			    int flags);
68static void FreeScreen(int scrnIndex, int flags);
69static void LeaveVT(int scrnIndex, int flags);
70static Bool SwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
71static Bool ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
72		       char **argv);
73static Bool PreInit(ScrnInfoPtr pScrn, int flags);
74
75typedef enum
76{
77    OPTION_SW_CURSOR,
78} modesettingOpts;
79
80static const OptionInfoRec Options[] = {
81    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
82    {-1, NULL, OPTV_NONE, {0}, FALSE}
83};
84
85/*
86 * Exported Xorg driver functions to winsys
87 */
88
89const OptionInfoRec *
90xorg_tracker_available_options(int chipid, int busid)
91{
92    return Options;
93}
94
95void
96xorg_tracker_set_functions(ScrnInfoPtr scrn)
97{
98    scrn->PreInit = PreInit;
99    scrn->ScreenInit = ScreenInit;
100    scrn->SwitchMode = SwitchMode;
101    scrn->AdjustFrame = AdjustFrame;
102    scrn->EnterVT = EnterVT;
103    scrn->LeaveVT = LeaveVT;
104    scrn->FreeScreen = FreeScreen;
105    scrn->ValidMode = ValidMode;
106}
107
108/*
109 * Static Xorg funtctions
110 */
111
112static Bool
113GetRec(ScrnInfoPtr pScrn)
114{
115    if (pScrn->driverPrivate)
116	return TRUE;
117
118    pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1);
119
120    return TRUE;
121}
122
123static void
124FreeRec(ScrnInfoPtr pScrn)
125{
126    if (!pScrn)
127	return;
128
129    if (!pScrn->driverPrivate)
130	return;
131
132    xfree(pScrn->driverPrivate);
133
134    pScrn->driverPrivate = NULL;
135}
136
137static void
138ProbeDDC(ScrnInfoPtr pScrn, int index)
139{
140    ConfiguredMonitor = NULL;
141}
142
143static Bool
144CreateFrontBuffer(ScrnInfoPtr pScrn)
145{
146    modesettingPtr ms = modesettingPTR(pScrn);
147    ScreenPtr pScreen = pScrn->pScreen;
148    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
149    unsigned handle, stride;
150
151    ms->noEvict = TRUE;
152    xorg_exa_set_displayed_usage(rootPixmap);
153    pScreen->ModifyPixmapHeader(rootPixmap,
154				pScrn->virtualX, pScrn->virtualY,
155				pScrn->depth, pScrn->bitsPerPixel,
156				pScrn->displayWidth * pScrn->bitsPerPixel / 8,
157				NULL);
158    ms->noEvict = FALSE;
159
160    handle = xorg_exa_get_pixmap_handle(rootPixmap, &stride);
161
162    drmModeAddFB(ms->fd,
163		 pScrn->virtualX,
164		 pScrn->virtualY,
165		 pScrn->depth,
166		 pScrn->bitsPerPixel,
167		 stride,
168		 handle,
169		 &ms->fb_id);
170
171    pScrn->frameX0 = 0;
172    pScrn->frameY0 = 0;
173    AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
174
175    return TRUE;
176}
177
178static Bool
179crtc_resize(ScrnInfoPtr pScrn, int width, int height)
180{
181    modesettingPtr ms = modesettingPTR(pScrn);
182    /*
183    ScreenPtr pScreen = pScrn->pScreen;
184    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
185    Bool fbAccessDisabled;
186    CARD8 *fbstart;
187     */
188
189    if (width == pScrn->virtualX && height == pScrn->virtualY)
190	return TRUE;
191
192    ErrorF("RESIZING TO %dx%d\n", width, height);
193
194    pScrn->virtualX = width;
195    pScrn->virtualY = height;
196
197    /* HW dependent - FIXME */
198    pScrn->displayWidth = pScrn->virtualX;
199
200    drmModeRmFB(ms->fd, ms->fb_id);
201
202    /* now create new frontbuffer */
203    return CreateFrontBuffer(pScrn);
204}
205
206static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
207    crtc_resize
208};
209
210static Bool
211PreInit(ScrnInfoPtr pScrn, int flags)
212{
213    xf86CrtcConfigPtr xf86_config;
214    modesettingPtr ms;
215    rgb defaultWeight = { 0, 0, 0 };
216    EntityInfoPtr pEnt;
217    EntPtr msEnt = NULL;
218    char *BusID;
219    int max_width, max_height;
220
221    if (pScrn->numEntities != 1)
222	return FALSE;
223
224    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
225
226    if (flags & PROBE_DETECT) {
227	ProbeDDC(pScrn, pEnt->index);
228	return TRUE;
229    }
230
231    /* Allocate driverPrivate */
232    if (!GetRec(pScrn))
233	return FALSE;
234
235    ms = modesettingPTR(pScrn);
236    ms->SaveGeneration = -1;
237    ms->pEnt = pEnt;
238
239    pScrn->displayWidth = 640;	       /* default it */
240
241    if (ms->pEnt->location.type != BUS_PCI)
242	return FALSE;
243
244    ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
245
246    /* Allocate an entity private if necessary */
247    if (xf86IsEntityShared(pScrn->entityList[0])) {
248	FatalError("Entity");
249#if 0
250	msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
251				     modesettingEntityIndex)->ptr;
252	ms->entityPrivate = msEnt;
253#else
254	(void)msEnt;
255#endif
256    } else
257	ms->entityPrivate = NULL;
258
259    if (xf86IsEntityShared(pScrn->entityList[0])) {
260	if (xf86IsPrimInitDone(pScrn->entityList[0])) {
261	    /* do something */
262	} else {
263	    xf86SetPrimInitDone(pScrn->entityList[0]);
264	}
265    }
266
267    BusID = xalloc(64);
268    sprintf(BusID, "PCI:%d:%d:%d",
269	    ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
270	    ms->PciInfo->dev, ms->PciInfo->func
271	);
272
273    ms->api = drm_api_create();
274    ms->fd = drmOpen(NULL, BusID);
275
276    if (ms->fd < 0)
277	return FALSE;
278
279    pScrn->monitor = pScrn->confScreen->monitor;
280    pScrn->progClock = TRUE;
281    pScrn->rgbBits = 8;
282
283    if (!xf86SetDepthBpp
284	(pScrn, 0, 0, 0,
285	 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
286	return FALSE;
287
288    switch (pScrn->depth) {
289    case 15:
290    case 16:
291    case 24:
292	break;
293    default:
294	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
295		   "Given depth (%d) is not supported by the driver\n",
296		   pScrn->depth);
297	return FALSE;
298    }
299    xf86PrintDepthBpp(pScrn);
300
301    if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
302	return FALSE;
303    if (!xf86SetDefaultVisual(pScrn, -1))
304	return FALSE;
305
306    /* Process the options */
307    xf86CollectOptions(pScrn, NULL);
308    if (!(ms->Options = xalloc(sizeof(Options))))
309	return FALSE;
310    memcpy(ms->Options, Options, sizeof(Options));
311    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
312
313    /* Allocate an xf86CrtcConfig */
314    xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
315    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
316
317    max_width = 8192;
318    max_height = 8192;
319    xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
320
321    if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
322	ms->SWCursor = TRUE;
323    }
324
325    SaveHWState(pScrn);
326
327    crtc_init(pScrn);
328    output_init(pScrn);
329
330    if (!xf86InitialConfiguration(pScrn, TRUE)) {
331	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
332	RestoreHWState(pScrn);
333	return FALSE;
334    }
335
336    RestoreHWState(pScrn);
337
338    /*
339     * If the driver can do gamma correction, it should call xf86SetGamma() here.
340     */
341    {
342	Gamma zeros = { 0.0, 0.0, 0.0 };
343
344	if (!xf86SetGamma(pScrn, zeros)) {
345	    return FALSE;
346	}
347    }
348
349    if (pScrn->modes == NULL) {
350	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
351	return FALSE;
352    }
353
354    pScrn->currentMode = pScrn->modes;
355
356    /* Set display resolution */
357    xf86SetDpi(pScrn, 0, 0);
358
359    /* Load the required sub modules */
360    if (!xf86LoadSubModule(pScrn, "fb")) {
361	return FALSE;
362    }
363
364    xf86LoadSubModule(pScrn, "exa");
365
366#ifdef DRI2
367    xf86LoadSubModule(pScrn, "dri2");
368#endif
369
370    return TRUE;
371}
372
373static Bool
374SaveHWState(ScrnInfoPtr pScrn)
375{
376    /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
377
378    return TRUE;
379}
380
381static Bool
382RestoreHWState(ScrnInfoPtr pScrn)
383{
384    /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
385
386    return TRUE;
387}
388
389static void xorgBlockHandler(int i, pointer blockData, pointer pTimeout,
390                             pointer pReadmask)
391{
392    ScreenPtr pScreen = screenInfo.screens[i];
393    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
394
395    pScreen->BlockHandler = ms->blockHandler;
396    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
397    pScreen->BlockHandler = xorgBlockHandler;
398
399    ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
400
401#ifdef DRM_MODE_FEATURE_DIRTYFB
402    {
403	RegionPtr dirty = DamageRegion(ms->damage);
404	unsigned num_cliprects = REGION_NUM_RECTS(dirty);
405
406	if (num_cliprects) {
407	    drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
408	    BoxPtr rect = REGION_RECTS(dirty);
409	    int i;
410
411	    for (i = 0; i < num_cliprects; i++, rect++) {
412		clip[i].x = rect->x1;
413		clip[i].y = rect->y1;
414		clip[i].width = rect->x2 - rect->x1;
415		clip[i].height = rect->y2 - rect->y1;
416	    }
417
418	    /* TODO query connector property to see if this is needed */
419	    drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
420
421	    DamageEmpty(ms->damage);
422	}
423    }
424#endif
425}
426
427static Bool
428CreateScreenResources(ScreenPtr pScreen)
429{
430    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
431    modesettingPtr ms = modesettingPTR(pScrn);
432    PixmapPtr rootPixmap;
433    Bool ret;
434    unsigned handle, stride;
435
436    ms->noEvict = TRUE;
437
438    pScreen->CreateScreenResources = ms->createScreenResources;
439    ret = pScreen->CreateScreenResources(pScreen);
440    pScreen->CreateScreenResources = CreateScreenResources;
441
442    rootPixmap = pScreen->GetScreenPixmap(pScreen);
443
444    xorg_exa_set_displayed_usage(rootPixmap);
445    xorg_exa_set_shared_usage(rootPixmap);
446    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
447	FatalError("Couldn't adjust screen pixmap\n");
448
449    ms->noEvict = FALSE;
450
451    handle = xorg_exa_get_pixmap_handle(rootPixmap, &stride);
452
453    drmModeAddFB(ms->fd,
454		 pScrn->virtualX,
455		 pScrn->virtualY,
456		 pScrn->depth,
457		 pScrn->bitsPerPixel,
458		 stride,
459		 handle,
460                 &ms->fb_id);
461
462    AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
463
464#ifdef DRM_MODE_FEATURE_DIRTYFB
465    ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
466                              pScreen, rootPixmap);
467
468    if (ms->damage) {
469       DamageRegister(&rootPixmap->drawable, ms->damage);
470
471       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
472    } else {
473       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
474                  "Failed to create screen damage record\n");
475       return FALSE;
476    }
477#endif
478
479    return ret;
480}
481
482static Bool
483ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
484{
485    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
486    modesettingPtr ms = modesettingPTR(pScrn);
487    VisualPtr visual;
488
489    /* deal with server regeneration */
490    if (ms->fd < 0) {
491	char *BusID;
492
493	BusID = xalloc(64);
494	sprintf(BusID, "PCI:%d:%d:%d",
495		((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
496		ms->PciInfo->dev, ms->PciInfo->func
497	    );
498
499	ms->fd = drmOpen(NULL, BusID);
500
501	if (ms->fd < 0)
502	    return FALSE;
503    }
504
505    if (!ms->screen) {
506	ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
507
508	if (!ms->screen) {
509	    FatalError("Could not init pipe_screen\n");
510	    return FALSE;
511	}
512    }
513
514    pScrn->pScreen = pScreen;
515
516    /* HW dependent - FIXME */
517    pScrn->displayWidth = pScrn->virtualX;
518
519    miClearVisualTypes();
520
521    if (!miSetVisualTypes(pScrn->depth,
522			  miGetDefaultVisualMask(pScrn->depth),
523			  pScrn->rgbBits, pScrn->defaultVisual))
524	return FALSE;
525
526    if (!miSetPixmapDepths())
527	return FALSE;
528
529    pScrn->memPhysBase = 0;
530    pScrn->fbOffset = 0;
531
532    if (!fbScreenInit(pScreen, NULL,
533		      pScrn->virtualX, pScrn->virtualY,
534		      pScrn->xDpi, pScrn->yDpi,
535		      pScrn->displayWidth, pScrn->bitsPerPixel))
536	return FALSE;
537
538    if (pScrn->bitsPerPixel > 8) {
539	/* Fixup RGB ordering */
540	visual = pScreen->visuals + pScreen->numVisuals;
541	while (--visual >= pScreen->visuals) {
542	    if ((visual->class | DynamicClass) == DirectColor) {
543		visual->offsetRed = pScrn->offset.red;
544		visual->offsetGreen = pScrn->offset.green;
545		visual->offsetBlue = pScrn->offset.blue;
546		visual->redMask = pScrn->mask.red;
547		visual->greenMask = pScrn->mask.green;
548		visual->blueMask = pScrn->mask.blue;
549	    }
550	}
551    }
552
553    fbPictureInit(pScreen, NULL, 0);
554
555    ms->blockHandler = pScreen->BlockHandler;
556    pScreen->BlockHandler = xorgBlockHandler;
557    ms->createScreenResources = pScreen->CreateScreenResources;
558    pScreen->CreateScreenResources = CreateScreenResources;
559
560    xf86SetBlackWhitePixels(pScreen);
561
562    ms->exa = xorg_exa_init(pScrn);
563
564    miInitializeBackingStore(pScreen);
565    xf86SetBackingStore(pScreen);
566    xf86SetSilkenMouse(pScreen);
567    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
568
569    /* Need to extend HWcursor support to handle mask interleave */
570    if (!ms->SWCursor)
571	xf86_cursors_init(pScreen, 64, 64,
572			  HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
573			  HARDWARE_CURSOR_ARGB);
574
575    /* Must force it before EnterVT, so we are in control of VT and
576     * later memory should be bound when allocating, e.g rotate_mem */
577    pScrn->vtSema = TRUE;
578
579    pScreen->SaveScreen = xf86SaveScreen;
580    ms->CloseScreen = pScreen->CloseScreen;
581    pScreen->CloseScreen = CloseScreen;
582
583    if (!xf86CrtcScreenInit(pScreen))
584	return FALSE;
585
586    if (!miCreateDefColormap(pScreen))
587	return FALSE;
588
589    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
590
591    if (serverGeneration == 1)
592	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
593
594#if 1
595#ifdef DRI2
596    driScreenInit(pScreen);
597#endif
598#endif
599
600    return EnterVT(scrnIndex, 1);
601}
602
603static void
604AdjustFrame(int scrnIndex, int x, int y, int flags)
605{
606    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
607    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
608    xf86OutputPtr output = config->output[config->compat_output];
609    xf86CrtcPtr crtc = output->crtc;
610
611    if (crtc && crtc->enabled) {
612	crtc->funcs->mode_set(crtc, pScrn->currentMode, pScrn->currentMode, x,
613			      y);
614	crtc->x = output->initial_x + x;
615	crtc->y = output->initial_y + y;
616    }
617}
618
619static void
620FreeScreen(int scrnIndex, int flags)
621{
622    FreeRec(xf86Screens[scrnIndex]);
623}
624
625static void
626LeaveVT(int scrnIndex, int flags)
627{
628    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
629    modesettingPtr ms = modesettingPTR(pScrn);
630    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
631    int o;
632
633    for (o = 0; o < config->num_crtc; o++) {
634	xf86CrtcPtr crtc = config->crtc[o];
635
636	crtc_cursor_destroy(crtc);
637
638	if (crtc->rotatedPixmap || crtc->rotatedData) {
639	    crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
640					crtc->rotatedData);
641	    crtc->rotatedPixmap = NULL;
642	    crtc->rotatedData = NULL;
643	}
644    }
645
646    drmModeRmFB(ms->fd, ms->fb_id);
647
648    RestoreHWState(pScrn);
649
650    if (drmDropMaster(ms->fd))
651	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
652		   "drmDropMaster failed: %s\n", strerror(errno));
653
654    pScrn->vtSema = FALSE;
655}
656
657/*
658 * This gets called when gaining control of the VT, and from ScreenInit().
659 */
660static Bool
661EnterVT(int scrnIndex, int flags)
662{
663    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
664    modesettingPtr ms = modesettingPTR(pScrn);
665
666    if (drmSetMaster(ms->fd)) {
667	if (errno == EINVAL) {
668	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
669		       "drmSetMaster failed: 2.6.29 or newer kernel required for "
670		       "multi-server DRI\n");
671	} else {
672	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
673		       "drmSetMaster failed: %s\n", strerror(errno));
674	}
675    }
676
677    /*
678     * Only save state once per server generation since that's what most
679     * drivers do.  Could change this to save state at each VT enter.
680     */
681    if (ms->SaveGeneration != serverGeneration) {
682	ms->SaveGeneration = serverGeneration;
683	SaveHWState(pScrn);
684    }
685
686    if (!flags)			       /* signals startup as we'll do this in CreateScreenResources */
687	CreateFrontBuffer(pScrn);
688
689    if (!xf86SetDesiredModes(pScrn))
690	return FALSE;
691
692    return TRUE;
693}
694
695static Bool
696SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
697{
698    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
699
700    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
701}
702
703static Bool
704CloseScreen(int scrnIndex, ScreenPtr pScreen)
705{
706    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
707    modesettingPtr ms = modesettingPTR(pScrn);
708
709    if (pScrn->vtSema) {
710	LeaveVT(scrnIndex, 0);
711    }
712#ifdef DRI2
713    driCloseScreen(pScreen);
714#endif
715
716    pScreen->BlockHandler = ms->blockHandler;
717    pScreen->CreateScreenResources = ms->createScreenResources;
718
719#ifdef DRM_MODE_FEATURE_DIRTYFB
720    if (ms->damage) {
721	DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
722	DamageDestroy(ms->damage);
723	ms->damage = NULL;
724    }
725#endif
726
727    if (ms->exa)
728	xorg_exa_close(pScrn);
729
730	ms->api->destroy(ms->api);
731	ms->api = NULL;
732    drmClose(ms->fd);
733    ms->fd = -1;
734
735    pScrn->vtSema = FALSE;
736    pScreen->CloseScreen = ms->CloseScreen;
737    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
738}
739
740static ModeStatus
741ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
742{
743    return MODE_OK;
744}
745
746/* vim: set sw=4 ts=8 sts=4: */
747