xorg_driver.c revision 53e314cb8057797ae75187d91836a50f61170dd7
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
59#ifdef HAVE_LIBKMS
60#include "libkms.h"
61#endif
62
63/*
64 * Functions and symbols exported to Xorg via pointers.
65 */
66
67static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
68static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
69			    char **argv);
70static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
71static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
72static Bool drv_enter_vt(int scrnIndex, int flags);
73static void drv_leave_vt(int scrnIndex, int flags);
74static void drv_free_screen(int scrnIndex, int flags);
75static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
76			         int flags);
77
78typedef enum
79{
80    OPTION_SW_CURSOR,
81    OPTION_2D_ACCEL,
82} drv_option_enums;
83
84static const OptionInfoRec drv_options[] = {
85    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
86    {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
87    {-1, NULL, OPTV_NONE, {0}, FALSE}
88};
89
90
91/*
92 * Exported Xorg driver functions to winsys
93 */
94
95const OptionInfoRec *
96xorg_tracker_available_options(int chipid, int busid)
97{
98    return drv_options;
99}
100
101void
102xorg_tracker_set_functions(ScrnInfoPtr scrn)
103{
104    scrn->PreInit = drv_pre_init;
105    scrn->ScreenInit = drv_screen_init;
106    scrn->SwitchMode = drv_switch_mode;
107    scrn->AdjustFrame = drv_adjust_frame;
108    scrn->EnterVT = drv_enter_vt;
109    scrn->LeaveVT = drv_leave_vt;
110    scrn->FreeScreen = drv_free_screen;
111    scrn->ValidMode = drv_valid_mode;
112}
113
114
115/*
116 * Internal function definitions
117 */
118
119static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn);
120static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
121static Bool drv_save_hw_state(ScrnInfoPtr pScrn);
122static Bool drv_restore_hw_state(ScrnInfoPtr pScrn);
123
124
125/*
126 * Internal functions
127 */
128
129static Bool
130drv_get_rec(ScrnInfoPtr pScrn)
131{
132    if (pScrn->driverPrivate)
133	return TRUE;
134
135    pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1);
136
137    return TRUE;
138}
139
140static void
141drv_free_rec(ScrnInfoPtr pScrn)
142{
143    if (!pScrn)
144	return;
145
146    if (!pScrn->driverPrivate)
147	return;
148
149    xfree(pScrn->driverPrivate);
150
151    pScrn->driverPrivate = NULL;
152}
153
154static void
155drv_probe_ddc(ScrnInfoPtr pScrn, int index)
156{
157    ConfiguredMonitor = NULL;
158}
159
160static Bool
161drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
162{
163    modesettingPtr ms = modesettingPTR(pScrn);
164    PixmapPtr rootPixmap;
165    ScreenPtr pScreen = pScrn->pScreen;
166
167    if (width == pScrn->virtualX && height == pScrn->virtualY)
168	return TRUE;
169
170    pScrn->virtualX = width;
171    pScrn->virtualY = height;
172
173    /*
174     * Remove the old framebuffer & texture.
175     */
176    drmModeRmFB(ms->fd, ms->fb_id);
177    if (!ms->destroy_front_buffer(pScrn))
178	FatalError("failed to destroy front buffer\n");
179
180    rootPixmap = pScreen->GetScreenPixmap(pScreen);
181    if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
182	return FALSE;
183
184    /* HW dependent - FIXME */
185    pScrn->displayWidth = pScrn->virtualX;
186
187    /* now create new frontbuffer */
188    return ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn);
189}
190
191static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
192    .resize = drv_crtc_resize
193};
194
195static Bool
196drv_init_drm(ScrnInfoPtr pScrn)
197{
198    modesettingPtr ms = modesettingPTR(pScrn);
199
200    /* deal with server regeneration */
201    if (ms->fd < 0) {
202	char *BusID;
203
204	BusID = xalloc(64);
205	sprintf(BusID, "PCI:%d:%d:%d",
206		((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
207		ms->PciInfo->dev, ms->PciInfo->func
208	    );
209
210	ms->fd = drmOpen(NULL, BusID);
211
212	if (ms->fd < 0)
213	    return FALSE;
214    }
215
216    return TRUE;
217}
218
219static Bool
220drv_init_resource_management(ScrnInfoPtr pScrn)
221{
222    modesettingPtr ms = modesettingPTR(pScrn);
223    /*
224    ScreenPtr pScreen = pScrn->pScreen;
225    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
226    Bool fbAccessDisabled;
227    CARD8 *fbstart;
228     */
229
230    if (ms->screen || ms->kms)
231	return TRUE;
232
233    ms->api = drm_api_create();
234    if (ms->api) {
235	ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
236
237	if (ms->screen)
238	    return TRUE;
239
240	if (ms->api->destroy)
241	    ms->api->destroy(ms->api);
242
243	ms->api = NULL;
244    }
245
246#ifdef HAVE_LIBKMS
247    if (!kms_create(ms->fd, &ms->kms))
248	return TRUE;
249#endif
250
251    return FALSE;
252}
253
254static Bool
255drv_close_resource_management(ScrnInfoPtr pScrn)
256{
257    modesettingPtr ms = modesettingPTR(pScrn);
258
259    if (ms->screen)
260	ms->screen->destroy(ms->screen);
261    ms->screen = NULL;
262
263    if (ms->api && ms->api->destroy)
264	ms->api->destroy(ms->api);
265    ms->api = NULL;
266
267#ifdef HAVE_LIBKMS
268    if (ms->kms)
269	kms_destroy(&ms->kms);
270#endif
271
272    return TRUE;
273}
274
275static Bool
276drv_pre_init(ScrnInfoPtr pScrn, int flags)
277{
278    xf86CrtcConfigPtr xf86_config;
279    modesettingPtr ms;
280    rgb defaultWeight = { 0, 0, 0 };
281    EntityInfoPtr pEnt;
282    EntPtr msEnt = NULL;
283    int max_width, max_height;
284
285    if (pScrn->numEntities != 1)
286	return FALSE;
287
288    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
289
290    if (flags & PROBE_DETECT) {
291	drv_probe_ddc(pScrn, pEnt->index);
292	return TRUE;
293    }
294
295    /* Allocate driverPrivate */
296    if (!drv_get_rec(pScrn))
297	return FALSE;
298
299    ms = modesettingPTR(pScrn);
300    ms->SaveGeneration = -1;
301    ms->pEnt = pEnt;
302
303    pScrn->displayWidth = 640;	       /* default it */
304
305    if (ms->pEnt->location.type != BUS_PCI)
306	return FALSE;
307
308    ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
309
310    /* Allocate an entity private if necessary */
311    if (xf86IsEntityShared(pScrn->entityList[0])) {
312	FatalError("Entity");
313#if 0
314	msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
315				     modesettingEntityIndex)->ptr;
316	ms->entityPrivate = msEnt;
317#else
318	(void)msEnt;
319#endif
320    } else
321	ms->entityPrivate = NULL;
322
323    if (xf86IsEntityShared(pScrn->entityList[0])) {
324	if (xf86IsPrimInitDone(pScrn->entityList[0])) {
325	    /* do something */
326	} else {
327	    xf86SetPrimInitDone(pScrn->entityList[0]);
328	}
329    }
330
331    ms->fd = -1;
332    ms->api = NULL;
333    if (!drv_init_drm(pScrn))
334	return FALSE;
335
336    pScrn->monitor = pScrn->confScreen->monitor;
337    pScrn->progClock = TRUE;
338    pScrn->rgbBits = 8;
339
340    if (!xf86SetDepthBpp
341	(pScrn, 0, 0, 0,
342	 PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
343	return FALSE;
344
345    switch (pScrn->depth) {
346    case 15:
347    case 16:
348    case 24:
349	break;
350    default:
351	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
352		   "Given depth (%d) is not supported by the driver\n",
353		   pScrn->depth);
354	return FALSE;
355    }
356    xf86PrintDepthBpp(pScrn);
357
358    if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
359	return FALSE;
360    if (!xf86SetDefaultVisual(pScrn, -1))
361	return FALSE;
362
363    /* Process the options */
364    xf86CollectOptions(pScrn, NULL);
365    if (!(ms->Options = xalloc(sizeof(drv_options))))
366	return FALSE;
367    memcpy(ms->Options, drv_options, sizeof(drv_options));
368    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
369
370    /* Allocate an xf86CrtcConfig */
371    xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
372    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
373
374    max_width = 8192;
375    max_height = 8192;
376    xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
377
378    if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
379	ms->SWCursor = TRUE;
380    }
381
382    drv_save_hw_state(pScrn);
383
384    xorg_crtc_init(pScrn);
385    xorg_output_init(pScrn);
386
387    if (!xf86InitialConfiguration(pScrn, TRUE)) {
388	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
389	drv_restore_hw_state(pScrn);
390	return FALSE;
391    }
392
393    drv_restore_hw_state(pScrn);
394
395    /*
396     * If the driver can do gamma correction, it should call xf86SetGamma() here.
397     */
398    {
399	Gamma zeros = { 0.0, 0.0, 0.0 };
400
401	if (!xf86SetGamma(pScrn, zeros)) {
402	    return FALSE;
403	}
404    }
405
406    if (pScrn->modes == NULL) {
407	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
408	return FALSE;
409    }
410
411    pScrn->currentMode = pScrn->modes;
412
413    /* Set display resolution */
414    xf86SetDpi(pScrn, 0, 0);
415
416    /* Load the required sub modules */
417    if (!xf86LoadSubModule(pScrn, "fb"))
418	return FALSE;
419
420    /* XXX: these aren't needed when we are using libkms */
421    if (!xf86LoadSubModule(pScrn, "exa"))
422	return FALSE;
423
424#ifdef DRI2
425    if (!xf86LoadSubModule(pScrn, "dri2"))
426	return FALSE;
427#endif
428
429    return TRUE;
430}
431
432static Bool
433drv_save_hw_state(ScrnInfoPtr pScrn)
434{
435    /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
436
437    return TRUE;
438}
439
440static Bool
441drv_restore_hw_state(ScrnInfoPtr pScrn)
442{
443    /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
444
445    return TRUE;
446}
447
448static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
449                              pointer pReadmask)
450{
451    ScreenPtr pScreen = screenInfo.screens[i];
452    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
453
454    pScreen->BlockHandler = ms->blockHandler;
455    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
456    pScreen->BlockHandler = drv_block_handler;
457
458    if (ms->ctx) {
459       int j;
460
461       ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, &ms->fence[XORG_NR_FENCES-1]);
462
463       if (ms->fence[0])
464          ms->ctx->screen->fence_finish(ms->ctx->screen, ms->fence[0], 0);
465
466       /* The amount of rendering generated by a block handler can be
467        * quite small.  Let us get a fair way ahead of hardware before
468        * throttling.
469        */
470       for (j = 0; j < XORG_NR_FENCES - 1; j++)
471          ms->screen->fence_reference(ms->screen,
472                                      &ms->fence[j],
473                                      ms->fence[j+1]);
474
475       ms->screen->fence_reference(ms->screen,
476                                   &ms->fence[XORG_NR_FENCES-1],
477                                   NULL);
478    }
479
480
481#ifdef DRM_MODE_FEATURE_DIRTYFB
482    {
483	RegionPtr dirty = DamageRegion(ms->damage);
484	unsigned num_cliprects = REGION_NUM_RECTS(dirty);
485
486	if (num_cliprects) {
487	    drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
488	    BoxPtr rect = REGION_RECTS(dirty);
489	    int i, ret;
490
491	    /* XXX no need for copy? */
492	    for (i = 0; i < num_cliprects; i++, rect++) {
493		clip[i].x1 = rect->x1;
494		clip[i].y1 = rect->y1;
495		clip[i].x2 = rect->x2;
496		clip[i].y2 = rect->y2;
497	    }
498
499	    /* TODO query connector property to see if this is needed */
500	    ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
501	    if (ret) {
502		debug_printf("%s: failed to send dirty (%i, %s)\n",
503			     __func__, ret, strerror(-ret));
504	    }
505
506	    DamageEmpty(ms->damage);
507	}
508    }
509#endif
510}
511
512static Bool
513drv_create_screen_resources(ScreenPtr pScreen)
514{
515    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
516    modesettingPtr ms = modesettingPTR(pScrn);
517    PixmapPtr rootPixmap;
518    Bool ret;
519
520    ms->noEvict = TRUE;
521
522    pScreen->CreateScreenResources = ms->createScreenResources;
523    ret = pScreen->CreateScreenResources(pScreen);
524    pScreen->CreateScreenResources = drv_create_screen_resources;
525
526    ms->bind_front_buffer(pScrn);
527
528    ms->noEvict = FALSE;
529
530    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
531
532#ifdef DRM_MODE_FEATURE_DIRTYFB
533    rootPixmap = pScreen->GetScreenPixmap(pScreen);
534    ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
535                              pScreen, rootPixmap);
536
537    if (ms->damage) {
538       DamageRegister(&rootPixmap->drawable, ms->damage);
539
540       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
541    } else {
542       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
543                  "Failed to create screen damage record\n");
544       return FALSE;
545    }
546#else
547    (void)rootPixmap;
548#endif
549
550    return ret;
551}
552
553static Bool
554drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
555{
556    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
557    modesettingPtr ms = modesettingPTR(pScrn);
558    VisualPtr visual;
559
560    if (!drv_init_drm(pScrn)) {
561	FatalError("Could not init DRM");
562	return FALSE;
563    }
564
565    if (!drv_init_resource_management(pScrn)) {
566	FatalError("Could not init resource management (!pipe_screen && !libkms)");
567	return FALSE;
568    }
569
570    if (!drv_init_front_buffer_functions(pScrn)) {
571	FatalError("Could not init front buffer manager");
572	return FALSE;
573    }
574
575    pScrn->pScreen = pScreen;
576
577    /* HW dependent - FIXME */
578    pScrn->displayWidth = pScrn->virtualX;
579
580    miClearVisualTypes();
581
582    if (!miSetVisualTypes(pScrn->depth,
583			  miGetDefaultVisualMask(pScrn->depth),
584			  pScrn->rgbBits, pScrn->defaultVisual))
585	return FALSE;
586
587    if (!miSetPixmapDepths())
588	return FALSE;
589
590    pScrn->memPhysBase = 0;
591    pScrn->fbOffset = 0;
592
593    if (!fbScreenInit(pScreen, NULL,
594		      pScrn->virtualX, pScrn->virtualY,
595		      pScrn->xDpi, pScrn->yDpi,
596		      pScrn->displayWidth, pScrn->bitsPerPixel))
597	return FALSE;
598
599    if (pScrn->bitsPerPixel > 8) {
600	/* Fixup RGB ordering */
601	visual = pScreen->visuals + pScreen->numVisuals;
602	while (--visual >= pScreen->visuals) {
603	    if ((visual->class | DynamicClass) == DirectColor) {
604		visual->offsetRed = pScrn->offset.red;
605		visual->offsetGreen = pScrn->offset.green;
606		visual->offsetBlue = pScrn->offset.blue;
607		visual->redMask = pScrn->mask.red;
608		visual->greenMask = pScrn->mask.green;
609		visual->blueMask = pScrn->mask.blue;
610	    }
611	}
612    }
613
614    fbPictureInit(pScreen, NULL, 0);
615
616    ms->blockHandler = pScreen->BlockHandler;
617    pScreen->BlockHandler = drv_block_handler;
618    ms->createScreenResources = pScreen->CreateScreenResources;
619    pScreen->CreateScreenResources = drv_create_screen_resources;
620
621    xf86SetBlackWhitePixels(pScreen);
622
623    if (ms->screen) {
624	ms->exa = xorg_exa_init(pScrn, xf86ReturnOptValBool(ms->Options,
625							    OPTION_2D_ACCEL, TRUE));
626	ms->debug_fallback = debug_get_bool_option("XORG_DEBUG_FALLBACK", TRUE);
627
628	xorg_xv_init(pScreen);
629#ifdef DRI2
630	xorg_dri2_init(pScreen);
631#endif
632    }
633
634    miInitializeBackingStore(pScreen);
635    xf86SetBackingStore(pScreen);
636    xf86SetSilkenMouse(pScreen);
637    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
638
639    /* Need to extend HWcursor support to handle mask interleave */
640    if (!ms->SWCursor)
641	xf86_cursors_init(pScreen, 64, 64,
642			  HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
643			  HARDWARE_CURSOR_ARGB);
644
645    /* Must force it before EnterVT, so we are in control of VT and
646     * later memory should be bound when allocating, e.g rotate_mem */
647    pScrn->vtSema = TRUE;
648
649    pScreen->SaveScreen = xf86SaveScreen;
650    ms->CloseScreen = pScreen->CloseScreen;
651    pScreen->CloseScreen = drv_close_screen;
652
653    if (!xf86CrtcScreenInit(pScreen))
654	return FALSE;
655
656    if (!miCreateDefColormap(pScreen))
657	return FALSE;
658
659    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
660
661    if (serverGeneration == 1)
662	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
663
664    if (ms->winsys_screen_init)
665	ms->winsys_screen_init(pScrn);
666
667    return drv_enter_vt(scrnIndex, 1);
668}
669
670static void
671drv_adjust_frame(int scrnIndex, int x, int y, int flags)
672{
673    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
674    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
675    xf86OutputPtr output = config->output[config->compat_output];
676    xf86CrtcPtr crtc = output->crtc;
677
678    if (crtc && crtc->enabled) {
679	crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
680				    RR_Rotate_0, x, y);
681	crtc->x = output->initial_x + x;
682	crtc->y = output->initial_y + y;
683    }
684}
685
686static void
687drv_free_screen(int scrnIndex, int flags)
688{
689    drv_free_rec(xf86Screens[scrnIndex]);
690}
691
692static void
693drv_leave_vt(int scrnIndex, int flags)
694{
695    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
696    modesettingPtr ms = modesettingPTR(pScrn);
697    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
698    int o;
699
700    if (ms->winsys_leave_vt)
701	ms->winsys_leave_vt(pScrn);
702
703    for (o = 0; o < config->num_crtc; o++) {
704	xf86CrtcPtr crtc = config->crtc[o];
705
706	xorg_crtc_cursor_destroy(crtc);
707
708	if (crtc->rotatedPixmap || crtc->rotatedData) {
709	    crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
710					crtc->rotatedData);
711	    crtc->rotatedPixmap = NULL;
712	    crtc->rotatedData = NULL;
713	}
714    }
715
716    drmModeRmFB(ms->fd, ms->fb_id);
717
718    drv_restore_hw_state(pScrn);
719
720    if (drmDropMaster(ms->fd))
721	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
722		   "drmDropMaster failed: %s\n", strerror(errno));
723
724    pScrn->vtSema = FALSE;
725}
726
727/*
728 * This gets called when gaining control of the VT, and from ScreenInit().
729 */
730static Bool
731drv_enter_vt(int scrnIndex, int flags)
732{
733    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
734    modesettingPtr ms = modesettingPTR(pScrn);
735
736    if (drmSetMaster(ms->fd)) {
737	if (errno == EINVAL) {
738	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
739		       "drmSetMaster failed: 2.6.29 or newer kernel required for "
740		       "multi-server DRI\n");
741	} else {
742	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
743		       "drmSetMaster failed: %s\n", strerror(errno));
744	}
745    }
746
747    /*
748     * Only save state once per server generation since that's what most
749     * drivers do.  Could change this to save state at each VT enter.
750     */
751    if (ms->SaveGeneration != serverGeneration) {
752	ms->SaveGeneration = serverGeneration;
753	drv_save_hw_state(pScrn);
754    }
755
756    if (!ms->create_front_buffer(pScrn))
757	return FALSE;
758
759    if (!flags && !ms->bind_front_buffer(pScrn))
760	return FALSE;
761
762    if (!xf86SetDesiredModes(pScrn))
763	return FALSE;
764
765    if (ms->winsys_enter_vt)
766	ms->winsys_enter_vt(pScrn);
767
768    return TRUE;
769}
770
771static Bool
772drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
773{
774    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
775
776    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
777}
778
779static Bool
780drv_close_screen(int scrnIndex, ScreenPtr pScreen)
781{
782    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
783    modesettingPtr ms = modesettingPTR(pScrn);
784
785    if (pScrn->vtSema) {
786	drv_leave_vt(scrnIndex, 0);
787    }
788
789    if (ms->winsys_screen_close)
790	ms->winsys_screen_close(pScrn);
791
792#ifdef DRI2
793    if (ms->screen)
794	xorg_dri2_close(pScreen);
795#endif
796
797    pScreen->BlockHandler = ms->blockHandler;
798    pScreen->CreateScreenResources = ms->createScreenResources;
799
800#ifdef DRM_MODE_FEATURE_DIRTYFB
801    if (ms->damage) {
802	DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
803	DamageDestroy(ms->damage);
804	ms->damage = NULL;
805    }
806#endif
807
808    drmModeRmFB(ms->fd, ms->fb_id);
809    ms->destroy_front_buffer(pScrn);
810
811    if (ms->exa)
812	xorg_exa_close(pScrn);
813    ms->exa = NULL;
814
815    drv_close_resource_management(pScrn);
816
817    drmClose(ms->fd);
818    ms->fd = -1;
819
820    pScrn->vtSema = FALSE;
821    pScreen->CloseScreen = ms->CloseScreen;
822    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
823}
824
825static ModeStatus
826drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
827{
828    return MODE_OK;
829}
830
831
832/*
833 * Front buffer backing store functions.
834 */
835
836static Bool
837drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn)
838{
839    modesettingPtr ms = modesettingPTR(pScrn);
840    pipe_texture_reference(&ms->root_texture, NULL);
841    return TRUE;
842}
843
844static Bool
845drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn)
846{
847    modesettingPtr ms = modesettingPTR(pScrn);
848    unsigned handle, stride;
849    struct pipe_texture *tex;
850    int ret;
851
852    ms->noEvict = TRUE;
853
854    tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY,
855				       pScrn->depth, pScrn->bitsPerPixel);
856
857    if (!tex)
858	return FALSE;
859
860    if (!ms->api->local_handle_from_texture(ms->api, ms->screen,
861					    tex,
862					    &stride,
863					    &handle))
864	goto err_destroy;
865
866    ret = drmModeAddFB(ms->fd,
867		       pScrn->virtualX,
868		       pScrn->virtualY,
869		       pScrn->depth,
870		       pScrn->bitsPerPixel,
871		       stride,
872		       handle,
873		       &ms->fb_id);
874    if (ret) {
875	debug_printf("%s: failed to create framebuffer (%i, %s)",
876		     __func__, ret, strerror(-ret));
877	goto err_destroy;
878    }
879
880    pScrn->frameX0 = 0;
881    pScrn->frameY0 = 0;
882    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
883
884    pipe_texture_reference(&ms->root_texture, tex);
885    pipe_texture_reference(&tex, NULL);
886
887    return TRUE;
888
889err_destroy:
890    pipe_texture_reference(&tex, NULL);
891    return FALSE;
892}
893
894static Bool
895drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn)
896{
897    modesettingPtr ms = modesettingPTR(pScrn);
898    ScreenPtr pScreen = pScrn->pScreen;
899    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
900    struct pipe_texture *check;
901
902    xorg_exa_set_displayed_usage(rootPixmap);
903    xorg_exa_set_shared_usage(rootPixmap);
904    xorg_exa_set_texture(rootPixmap, ms->root_texture);
905    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
906	FatalError("Couldn't adjust screen pixmap\n");
907
908    check = xorg_exa_get_texture(rootPixmap);
909    if (ms->root_texture != check)
910	FatalError("Created new root texture\n");
911
912    pipe_texture_reference(&check, NULL);
913    return TRUE;
914}
915
916#ifdef HAVE_LIBKMS
917static Bool
918drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn)
919{
920    modesettingPtr ms = modesettingPTR(pScrn);
921    ScreenPtr pScreen = pScrn->pScreen;
922    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
923
924    if (!ms->root_bo)
925	return TRUE;
926
927    kms_bo_unmap(ms->root_bo);
928    kms_bo_destroy(&ms->root_bo);
929    return TRUE;
930}
931
932static Bool
933drv_create_front_buffer_kms(ScrnInfoPtr pScrn)
934{
935    modesettingPtr ms = modesettingPTR(pScrn);
936    unsigned handle, stride;
937    struct kms_bo *bo;
938    unsigned attr[8];
939    int ret;
940
941    attr[0] = KMS_BO_TYPE;
942    attr[1] = KMS_BO_TYPE_SCANOUT;
943    attr[2] = KMS_WIDTH;
944    attr[3] = pScrn->virtualX;
945    attr[4] = KMS_HEIGHT;
946    attr[5] = pScrn->virtualY;
947    attr[6] = 0;
948
949    if (kms_bo_create(ms->kms, attr, &bo))
950	return FALSE;
951
952    if (kms_bo_get_prop(bo, KMS_PITCH, &stride))
953	goto err_destroy;
954
955    if (kms_bo_get_prop(bo, KMS_HANDLE, &handle))
956	goto err_destroy;
957
958    ret = drmModeAddFB(ms->fd,
959		       pScrn->virtualX,
960		       pScrn->virtualY,
961		       pScrn->depth,
962		       pScrn->bitsPerPixel,
963		       stride,
964		       handle,
965		       &ms->fb_id);
966    if (ret) {
967	debug_printf("%s: failed to create framebuffer (%i, %s)",
968		     __func__, ret, strerror(-ret));
969	goto err_destroy;
970    }
971
972    pScrn->frameX0 = 0;
973    pScrn->frameY0 = 0;
974    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
975    ms->root_bo = bo;
976
977    return TRUE;
978
979err_destroy:
980    kms_bo_destroy(&bo);
981    return FALSE;
982}
983
984static Bool
985drv_bind_front_buffer_kms(ScrnInfoPtr pScrn)
986{
987    modesettingPtr ms = modesettingPTR(pScrn);
988    ScreenPtr pScreen = pScrn->pScreen;
989    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
990    unsigned stride;
991    void *ptr;
992
993    if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride))
994	return FALSE;
995
996    if (kms_bo_map(ms->root_bo, &ptr))
997	goto err_destroy;
998
999    pScreen->ModifyPixmapHeader(rootPixmap,
1000				pScreen->width,
1001				pScreen->height,
1002				pScreen->rootDepth,
1003				pScrn->bitsPerPixel,
1004				stride,
1005				ptr);
1006    return TRUE;
1007
1008err_destroy:
1009    kms_bo_destroy(&ms->root_bo);
1010    return FALSE;
1011}
1012#endif /* HAVE_LIBKMS */
1013
1014static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn)
1015{
1016    modesettingPtr ms = modesettingPTR(pScrn);
1017    if (ms->screen) {
1018	ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d;
1019	ms->create_front_buffer = drv_create_front_buffer_ga3d;
1020	ms->bind_front_buffer = drv_bind_front_buffer_ga3d;
1021#ifdef HAVE_LIBKMS
1022    } else if (ms->kms) {
1023	ms->destroy_front_buffer = drv_destroy_front_buffer_kms;
1024	ms->create_front_buffer = drv_create_front_buffer_kms;
1025	ms->bind_front_buffer = drv_bind_front_buffer_kms;
1026#endif
1027    } else
1028	return FALSE;
1029
1030    return TRUE;
1031}
1032
1033/* vim: set sw=4 ts=8 sts=4: */
1034