xorg_driver.c revision c0cf0fd163397d68acfb2e226a6b9a569ded54cd
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    //ScreenPtr pScreen = pScrn->pScreen;
183    //PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
184    //Bool fbAccessDisabled;
185    //CARD8 *fbstart;
186
187    if (width == pScrn->virtualX && height == pScrn->virtualY)
188	return TRUE;
189
190    ErrorF("RESIZING TO %dx%d\n", width, height);
191
192    pScrn->virtualX = width;
193    pScrn->virtualY = height;
194
195    /* HW dependent - FIXME */
196    pScrn->displayWidth = pScrn->virtualX;
197
198    drmModeRmFB(ms->fd, ms->fb_id);
199
200    /* now create new frontbuffer */
201    return CreateFrontBuffer(pScrn);
202}
203
204static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
205    crtc_resize
206};
207
208static Bool
209PreInit(ScrnInfoPtr pScrn, int flags)
210{
211    xf86CrtcConfigPtr xf86_config;
212    modesettingPtr ms;
213    rgb defaultWeight = { 0, 0, 0 };
214    EntityInfoPtr pEnt;
215    EntPtr msEnt = NULL;
216    char *BusID;
217    int max_width, max_height;
218
219    if (pScrn->numEntities != 1)
220	return FALSE;
221
222    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
223
224    if (flags & PROBE_DETECT) {
225	ProbeDDC(pScrn, pEnt->index);
226	return TRUE;
227    }
228
229    /* Allocate driverPrivate */
230    if (!GetRec(pScrn))
231	return FALSE;
232
233    ms = modesettingPTR(pScrn);
234    ms->SaveGeneration = -1;
235    ms->pEnt = pEnt;
236
237    pScrn->displayWidth = 640;	       /* default it */
238
239    if (ms->pEnt->location.type != BUS_PCI)
240	return FALSE;
241
242    ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
243
244    /* Allocate an entity private if necessary */
245    if (xf86IsEntityShared(pScrn->entityList[0])) {
246	FatalError("Entity");
247#if 0
248	msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
249				     modesettingEntityIndex)->ptr;
250	ms->entityPrivate = msEnt;
251#else
252	(void)msEnt;
253#endif
254    } else
255	ms->entityPrivate = NULL;
256
257    if (xf86IsEntityShared(pScrn->entityList[0])) {
258	if (xf86IsPrimInitDone(pScrn->entityList[0])) {
259	    /* do something */
260	} else {
261	    xf86SetPrimInitDone(pScrn->entityList[0]);
262	}
263    }
264
265    BusID = xalloc(64);
266    sprintf(BusID, "PCI:%d:%d:%d",
267	    ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
268	    ms->PciInfo->dev, ms->PciInfo->func
269	);
270
271    ms->api = drm_api_create();
272    ms->fd = drmOpen(NULL, BusID);
273
274    if (ms->fd < 0)
275	return FALSE;
276
277    pScrn->monitor = pScrn->confScreen->monitor;
278    pScrn->progClock = TRUE;
279    pScrn->rgbBits = 8;
280
281    if (!xf86SetDepthBpp
282	(pScrn, 0, 0, 0,
283	 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
284	return FALSE;
285
286    switch (pScrn->depth) {
287    case 15:
288    case 16:
289    case 24:
290	break;
291    default:
292	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
293		   "Given depth (%d) is not supported by the driver\n",
294		   pScrn->depth);
295	return FALSE;
296    }
297    xf86PrintDepthBpp(pScrn);
298
299    if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
300	return FALSE;
301    if (!xf86SetDefaultVisual(pScrn, -1))
302	return FALSE;
303
304    /* Process the options */
305    xf86CollectOptions(pScrn, NULL);
306    if (!(ms->Options = xalloc(sizeof(Options))))
307	return FALSE;
308    memcpy(ms->Options, Options, sizeof(Options));
309    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
310
311    /* Allocate an xf86CrtcConfig */
312    xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
313    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
314
315    max_width = 8192;
316    max_height = 8192;
317    xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
318
319    if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
320	ms->SWCursor = TRUE;
321    }
322
323    SaveHWState(pScrn);
324
325    crtc_init(pScrn);
326    output_init(pScrn);
327
328    if (!xf86InitialConfiguration(pScrn, TRUE)) {
329	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
330	RestoreHWState(pScrn);
331	return FALSE;
332    }
333
334    RestoreHWState(pScrn);
335
336    /*
337     * If the driver can do gamma correction, it should call xf86SetGamma() here.
338     */
339    {
340	Gamma zeros = { 0.0, 0.0, 0.0 };
341
342	if (!xf86SetGamma(pScrn, zeros)) {
343	    return FALSE;
344	}
345    }
346
347    if (pScrn->modes == NULL) {
348	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
349	return FALSE;
350    }
351
352    pScrn->currentMode = pScrn->modes;
353
354    /* Set display resolution */
355    xf86SetDpi(pScrn, 0, 0);
356
357    /* Load the required sub modules */
358    if (!xf86LoadSubModule(pScrn, "fb")) {
359	return FALSE;
360    }
361
362    xf86LoadSubModule(pScrn, "exa");
363
364#ifdef DRI2
365    xf86LoadSubModule(pScrn, "dri2");
366#endif
367
368    return TRUE;
369}
370
371static Bool
372SaveHWState(ScrnInfoPtr pScrn)
373{
374    /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
375
376    return TRUE;
377}
378
379static Bool
380RestoreHWState(ScrnInfoPtr pScrn)
381{
382    /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
383
384    return TRUE;
385}
386
387static void xorgBlockHandler(int i, pointer blockData, pointer pTimeout,
388                             pointer pReadmask)
389{
390    ScreenPtr pScreen = screenInfo.screens[i];
391    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
392
393    pScreen->BlockHandler = ms->blockHandler;
394    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
395    pScreen->BlockHandler = xorgBlockHandler;
396
397    ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
398
399#ifdef DRM_MODE_FEATURE_DIRTYFB
400    {
401	RegionPtr dirty = DamageRegion(ms->damage);
402	unsigned num_cliprects = REGION_NUM_RECTS(dirty);
403
404	if (num_cliprects) {
405	    drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
406	    BoxPtr rect = REGION_RECTS(dirty);
407	    int i;
408
409	    for (i = 0; i < num_cliprects; i++, rect++) {
410		clip[i].x = rect->x1;
411		clip[i].y = rect->y1;
412		clip[i].width = rect->x2 - rect->x1;
413		clip[i].height = rect->y2 - rect->y1;
414	    }
415
416	    /* TODO query connector property to see if this is needed */
417	    drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
418
419	    DamageEmpty(ms->damage);
420	}
421    }
422#endif
423}
424
425static Bool
426CreateScreenResources(ScreenPtr pScreen)
427{
428    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
429    modesettingPtr ms = modesettingPTR(pScrn);
430    PixmapPtr rootPixmap;
431    Bool ret;
432    unsigned handle, stride;
433
434    ms->noEvict = TRUE;
435
436    pScreen->CreateScreenResources = ms->createScreenResources;
437    ret = pScreen->CreateScreenResources(pScreen);
438    pScreen->CreateScreenResources = CreateScreenResources;
439
440    rootPixmap = pScreen->GetScreenPixmap(pScreen);
441
442    xorg_exa_set_displayed_usage(rootPixmap);
443    xorg_exa_set_shared_usage(rootPixmap);
444    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
445	FatalError("Couldn't adjust screen pixmap\n");
446
447    ms->noEvict = FALSE;
448
449    handle = xorg_exa_get_pixmap_handle(rootPixmap, &stride);
450
451    drmModeAddFB(ms->fd,
452		 pScrn->virtualX,
453		 pScrn->virtualY,
454		 pScrn->depth,
455		 pScrn->bitsPerPixel,
456		 stride,
457		 handle,
458                 &ms->fb_id);
459
460    AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
461
462#ifdef DRM_MODE_FEATURE_DIRTYFB
463    ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
464                              pScreen, rootPixmap);
465
466    if (ms->damage) {
467       DamageRegister(&rootPixmap->drawable, ms->damage);
468
469       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
470    } else {
471       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
472                  "Failed to create screen damage record\n");
473       return FALSE;
474    }
475#endif
476
477    return ret;
478}
479
480static Bool
481ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
482{
483    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
484    modesettingPtr ms = modesettingPTR(pScrn);
485    VisualPtr visual;
486
487    /* deal with server regeneration */
488    if (ms->fd < 0) {
489	char *BusID;
490
491	BusID = xalloc(64);
492	sprintf(BusID, "PCI:%d:%d:%d",
493		((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
494		ms->PciInfo->dev, ms->PciInfo->func
495	    );
496
497	ms->fd = drmOpen(NULL, BusID);
498
499	if (ms->fd < 0)
500	    return FALSE;
501    }
502
503    if (!ms->screen) {
504	ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
505
506	if (!ms->screen) {
507	    FatalError("Could not init pipe_screen\n");
508	    return FALSE;
509	}
510    }
511
512    pScrn->pScreen = pScreen;
513
514    /* HW dependent - FIXME */
515    pScrn->displayWidth = pScrn->virtualX;
516
517    miClearVisualTypes();
518
519    if (!miSetVisualTypes(pScrn->depth,
520			  miGetDefaultVisualMask(pScrn->depth),
521			  pScrn->rgbBits, pScrn->defaultVisual))
522	return FALSE;
523
524    if (!miSetPixmapDepths())
525	return FALSE;
526
527    pScrn->memPhysBase = 0;
528    pScrn->fbOffset = 0;
529
530    if (!fbScreenInit(pScreen, NULL,
531		      pScrn->virtualX, pScrn->virtualY,
532		      pScrn->xDpi, pScrn->yDpi,
533		      pScrn->displayWidth, pScrn->bitsPerPixel))
534	return FALSE;
535
536    if (pScrn->bitsPerPixel > 8) {
537	/* Fixup RGB ordering */
538	visual = pScreen->visuals + pScreen->numVisuals;
539	while (--visual >= pScreen->visuals) {
540	    if ((visual->class | DynamicClass) == DirectColor) {
541		visual->offsetRed = pScrn->offset.red;
542		visual->offsetGreen = pScrn->offset.green;
543		visual->offsetBlue = pScrn->offset.blue;
544		visual->redMask = pScrn->mask.red;
545		visual->greenMask = pScrn->mask.green;
546		visual->blueMask = pScrn->mask.blue;
547	    }
548	}
549    }
550
551    fbPictureInit(pScreen, NULL, 0);
552
553    ms->blockHandler = pScreen->BlockHandler;
554    pScreen->BlockHandler = xorgBlockHandler;
555    ms->createScreenResources = pScreen->CreateScreenResources;
556    pScreen->CreateScreenResources = CreateScreenResources;
557
558    xf86SetBlackWhitePixels(pScreen);
559
560    ms->exa = xorg_exa_init(pScrn);
561
562    miInitializeBackingStore(pScreen);
563    xf86SetBackingStore(pScreen);
564    xf86SetSilkenMouse(pScreen);
565    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
566
567    /* Need to extend HWcursor support to handle mask interleave */
568    if (!ms->SWCursor)
569	xf86_cursors_init(pScreen, 64, 64,
570			  HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
571			  HARDWARE_CURSOR_ARGB);
572
573    /* Must force it before EnterVT, so we are in control of VT and
574     * later memory should be bound when allocating, e.g rotate_mem */
575    pScrn->vtSema = TRUE;
576
577    pScreen->SaveScreen = xf86SaveScreen;
578    ms->CloseScreen = pScreen->CloseScreen;
579    pScreen->CloseScreen = CloseScreen;
580
581    if (!xf86CrtcScreenInit(pScreen))
582	return FALSE;
583
584    if (!miCreateDefColormap(pScreen))
585	return FALSE;
586
587    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
588
589    if (serverGeneration == 1)
590	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
591
592#if 1
593#ifdef DRI2
594    driScreenInit(pScreen);
595#endif
596#endif
597
598    return EnterVT(scrnIndex, 1);
599}
600
601static void
602AdjustFrame(int scrnIndex, int x, int y, int flags)
603{
604    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
605    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
606    xf86OutputPtr output = config->output[config->compat_output];
607    xf86CrtcPtr crtc = output->crtc;
608
609    if (crtc && crtc->enabled) {
610	crtc->funcs->mode_set(crtc, pScrn->currentMode, pScrn->currentMode, x,
611			      y);
612	crtc->x = output->initial_x + x;
613	crtc->y = output->initial_y + y;
614    }
615}
616
617static void
618FreeScreen(int scrnIndex, int flags)
619{
620    FreeRec(xf86Screens[scrnIndex]);
621}
622
623static void
624LeaveVT(int scrnIndex, int flags)
625{
626    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
627    modesettingPtr ms = modesettingPTR(pScrn);
628    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
629    int o;
630
631    for (o = 0; o < config->num_crtc; o++) {
632	xf86CrtcPtr crtc = config->crtc[o];
633
634	crtc_cursor_destroy(crtc);
635
636	if (crtc->rotatedPixmap || crtc->rotatedData) {
637	    crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
638					crtc->rotatedData);
639	    crtc->rotatedPixmap = NULL;
640	    crtc->rotatedData = NULL;
641	}
642    }
643
644    drmModeRmFB(ms->fd, ms->fb_id);
645
646    RestoreHWState(pScrn);
647
648    if (drmDropMaster(ms->fd))
649	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
650		   "drmDropMaster failed: %s\n", strerror(errno));
651
652    pScrn->vtSema = FALSE;
653}
654
655/*
656 * This gets called when gaining control of the VT, and from ScreenInit().
657 */
658static Bool
659EnterVT(int scrnIndex, int flags)
660{
661    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
662    modesettingPtr ms = modesettingPTR(pScrn);
663
664    if (drmSetMaster(ms->fd)) {
665	if (errno == EINVAL) {
666	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
667		       "drmSetMaster failed: 2.6.29 or newer kernel required for "
668		       "multi-server DRI\n");
669	} else {
670	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
671		       "drmSetMaster failed: %s\n", strerror(errno));
672	}
673    }
674
675    /*
676     * Only save state once per server generation since that's what most
677     * drivers do.  Could change this to save state at each VT enter.
678     */
679    if (ms->SaveGeneration != serverGeneration) {
680	ms->SaveGeneration = serverGeneration;
681	SaveHWState(pScrn);
682    }
683
684    if (!flags)			       /* signals startup as we'll do this in CreateScreenResources */
685	CreateFrontBuffer(pScrn);
686
687    if (!xf86SetDesiredModes(pScrn))
688	return FALSE;
689
690    return TRUE;
691}
692
693static Bool
694SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
695{
696    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
697
698    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
699}
700
701static Bool
702CloseScreen(int scrnIndex, ScreenPtr pScreen)
703{
704    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
705    modesettingPtr ms = modesettingPTR(pScrn);
706
707    if (pScrn->vtSema) {
708	LeaveVT(scrnIndex, 0);
709    }
710#ifdef DRI2
711    driCloseScreen(pScreen);
712#endif
713
714    pScreen->BlockHandler = ms->blockHandler;
715    pScreen->CreateScreenResources = ms->createScreenResources;
716
717#ifdef DRM_MODE_FEATURE_DIRTYFB
718    if (ms->damage) {
719	DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
720	DamageDestroy(ms->damage);
721	ms->damage = NULL;
722    }
723#endif
724
725    if (ms->exa)
726	xorg_exa_close(pScrn);
727
728	ms->api->destroy(ms->api);
729	ms->api = NULL;
730    drmClose(ms->fd);
731    ms->fd = -1;
732
733    pScrn->vtSema = FALSE;
734    pScreen->CloseScreen = ms->CloseScreen;
735    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
736}
737
738static ModeStatus
739ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
740{
741    return MODE_OK;
742}
743
744/* vim: set sw=4 ts=8 sts=4: */
745