1428d7b3dSmrg/**************************************************************************
2428d7b3dSmrg
3428d7b3dSmrgCopyright 2001 VA Linux Systems Inc., Fremont, California.
4428d7b3dSmrgCopyright © 2002 by David Dawes
5428d7b3dSmrg
6428d7b3dSmrgAll Rights Reserved.
7428d7b3dSmrg
8428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a
9428d7b3dSmrgcopy of this software and associated documentation files (the "Software"),
10428d7b3dSmrgto deal in the Software without restriction, including without limitation
11428d7b3dSmrgon the rights to use, copy, modify, merge, publish, distribute, sub
12428d7b3dSmrglicense, and/or sell copies of the Software, and to permit persons to whom
13428d7b3dSmrgthe Software is furnished to do so, subject to the following conditions:
14428d7b3dSmrg
15428d7b3dSmrgThe above copyright notice and this permission notice (including the next
16428d7b3dSmrgparagraph) shall be included in all copies or substantial portions of the
17428d7b3dSmrgSoftware.
18428d7b3dSmrg
19428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20428d7b3dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21428d7b3dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22428d7b3dSmrgTHE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23428d7b3dSmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24428d7b3dSmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25428d7b3dSmrgUSE OR OTHER DEALINGS IN THE SOFTWARE.
26428d7b3dSmrg
27428d7b3dSmrg**************************************************************************/
28428d7b3dSmrg
29428d7b3dSmrg/*
30428d7b3dSmrg * Authors: Jeff Hartmann <jhartmann@valinux.com>
31428d7b3dSmrg *          Abraham van der Merwe <abraham@2d3d.co.za>
32428d7b3dSmrg *          David Dawes <dawes@xfree86.org>
33428d7b3dSmrg *          Alan Hourihane <alanh@tungstengraphics.com>
34428d7b3dSmrg */
35428d7b3dSmrg
36428d7b3dSmrg#ifdef HAVE_CONFIG_H
37428d7b3dSmrg#include "config.h"
38428d7b3dSmrg#endif
39428d7b3dSmrg
40428d7b3dSmrg#include <string.h>
41428d7b3dSmrg#include <stdio.h>
42428d7b3dSmrg#include <unistd.h>
43428d7b3dSmrg#include <stdlib.h>
44428d7b3dSmrg#include <stdio.h>
45428d7b3dSmrg#include <errno.h>
46428d7b3dSmrg
47428d7b3dSmrg#include "sna.h"
48428d7b3dSmrg#include "sna_module.h"
49428d7b3dSmrg#include "sna_video.h"
50428d7b3dSmrg
51428d7b3dSmrg#include "intel_driver.h"
52428d7b3dSmrg#include "intel_options.h"
53428d7b3dSmrg
54428d7b3dSmrg#include <xf86cmap.h>
55428d7b3dSmrg#include <xf86drm.h>
56428d7b3dSmrg#include <xf86RandR12.h>
57428d7b3dSmrg#include <mi.h>
58428d7b3dSmrg#include <micmap.h>
59428d7b3dSmrg
60428d7b3dSmrg#include <sys/ioctl.h>
61428d7b3dSmrg#include <sys/fcntl.h>
62428d7b3dSmrg#include <sys/poll.h>
63428d7b3dSmrg#include "i915_drm.h"
64428d7b3dSmrg
65428d7b3dSmrg#ifdef HAVE_VALGRIND
66428d7b3dSmrg#include <valgrind.h>
67428d7b3dSmrg#include <memcheck.h>
68428d7b3dSmrg#endif
69428d7b3dSmrg
70428d7b3dSmrg#if HAVE_DOT_GIT
71428d7b3dSmrg#include "git_version.h"
72428d7b3dSmrg#endif
73428d7b3dSmrg
74428d7b3dSmrg#ifdef TEARFREE
75428d7b3dSmrg#define ENABLE_TEAR_FREE TRUE
76428d7b3dSmrg#else
77428d7b3dSmrg#define ENABLE_TEAR_FREE FALSE
78428d7b3dSmrg#endif
79428d7b3dSmrg
80428d7b3dSmrgDevPrivateKeyRec sna_pixmap_key;
81428d7b3dSmrgDevPrivateKeyRec sna_gc_key;
82428d7b3dSmrgDevPrivateKeyRec sna_window_key;
83428d7b3dSmrgDevPrivateKeyRec sna_glyph_key;
84428d7b3dSmrgDevPrivateKeyRec sna_client_key;
85428d7b3dSmrg
86428d7b3dSmrgstatic void
87428d7b3dSmrgsna_load_palette(ScrnInfoPtr scrn, int numColors, int *indices,
88428d7b3dSmrg		 LOCO * colors, VisualPtr pVisual)
89428d7b3dSmrg{
90428d7b3dSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
91428d7b3dSmrg	int p, n, i, j;
92428d7b3dSmrg	uint16_t lut_r[256], lut_g[256], lut_b[256];
93428d7b3dSmrg
94428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
95428d7b3dSmrg
96428d7b3dSmrg	for (p = 0; p < xf86_config->num_crtc; p++) {
97428d7b3dSmrg		xf86CrtcPtr crtc = xf86_config->crtc[p];
98428d7b3dSmrg
99428d7b3dSmrg#define C(I,RGB) (colors[I].RGB << 8 | colors[I].RGB)
100428d7b3dSmrg		switch (scrn->depth) {
101428d7b3dSmrg		case 15:
102428d7b3dSmrg			for (n = 0; n < numColors; n++) {
103428d7b3dSmrg				i = indices[n];
104428d7b3dSmrg				for (j = 0; j < 8; j++) {
105428d7b3dSmrg					lut_r[8*i + j] = C(i, red);
106428d7b3dSmrg					lut_g[8*i + j] = C(i, green);
107428d7b3dSmrg					lut_b[8*i + j] = C(i, blue);
108428d7b3dSmrg				}
109428d7b3dSmrg			}
110428d7b3dSmrg			break;
111428d7b3dSmrg		case 16:
112428d7b3dSmrg			for (n = 0; n < numColors; n++) {
113428d7b3dSmrg				i = indices[n];
114428d7b3dSmrg
115428d7b3dSmrg				if (i <= 31) {
116428d7b3dSmrg					for (j = 0; j < 8; j++) {
117428d7b3dSmrg						lut_r[8*i + j] = C(i, red);
118428d7b3dSmrg						lut_b[8*i + j] = C(i, blue);
119428d7b3dSmrg					}
120428d7b3dSmrg				}
121428d7b3dSmrg
122428d7b3dSmrg				for (j = 0; j < 4; j++)
123428d7b3dSmrg					lut_g[4*i + j] = C(i, green);
124428d7b3dSmrg			}
125428d7b3dSmrg			break;
126428d7b3dSmrg		default:
127428d7b3dSmrg			for (n = 0; n < numColors; n++) {
128428d7b3dSmrg				i = indices[n];
129428d7b3dSmrg				lut_r[i] = C(i, red);
130428d7b3dSmrg				lut_g[i] = C(i, green);
131428d7b3dSmrg				lut_b[i] = C(i, blue);
132428d7b3dSmrg			}
133428d7b3dSmrg			break;
134428d7b3dSmrg		}
135428d7b3dSmrg#undef C
136428d7b3dSmrg
137428d7b3dSmrg		/* Make the change through RandR */
138428d7b3dSmrg#ifdef RANDR_12_INTERFACE
139428d7b3dSmrg		RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
140428d7b3dSmrg#else
141428d7b3dSmrg		crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
142428d7b3dSmrg#endif
143428d7b3dSmrg	}
144428d7b3dSmrg}
145428d7b3dSmrg
146428d7b3dSmrgstatic void
147428d7b3dSmrgsna_set_fallback_mode(ScrnInfoPtr scrn)
148428d7b3dSmrg{
149428d7b3dSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
150428d7b3dSmrg	xf86OutputPtr output = NULL;
151428d7b3dSmrg	xf86CrtcPtr crtc = NULL;
152428d7b3dSmrg	int n;
153428d7b3dSmrg
154428d7b3dSmrg	if ((unsigned)config->compat_output < config->num_output) {
155428d7b3dSmrg		output = config->output[config->compat_output];
156428d7b3dSmrg		crtc = output->crtc;
157428d7b3dSmrg	}
158428d7b3dSmrg
159428d7b3dSmrg	for (n = 0; n < config->num_output; n++)
160428d7b3dSmrg		config->output[n]->crtc = NULL;
161428d7b3dSmrg	for (n = 0; n < config->num_crtc; n++)
162428d7b3dSmrg		config->crtc[n]->enabled = FALSE;
163428d7b3dSmrg
164428d7b3dSmrg	if (output && crtc) {
165428d7b3dSmrg		DisplayModePtr mode;
166428d7b3dSmrg
167428d7b3dSmrg		output->crtc = crtc;
168428d7b3dSmrg
169428d7b3dSmrg		mode = xf86OutputFindClosestMode(output, scrn->currentMode);
170428d7b3dSmrg		if (mode &&
171428d7b3dSmrg		    xf86CrtcSetModeTransform(crtc, mode, RR_Rotate_0, NULL, 0, 0)) {
172428d7b3dSmrg			crtc->desiredMode = *mode;
173428d7b3dSmrg			crtc->desiredMode.prev = crtc->desiredMode.next = NULL;
174428d7b3dSmrg			crtc->desiredMode.name = NULL;
175428d7b3dSmrg			crtc->desiredMode.PrivSize = 0;
176428d7b3dSmrg			crtc->desiredMode.PrivFlags = 0;
177428d7b3dSmrg			crtc->desiredMode.Private = NULL;
178428d7b3dSmrg			crtc->desiredRotation = RR_Rotate_0;
179428d7b3dSmrg			crtc->desiredTransformPresent = FALSE;
180428d7b3dSmrg			crtc->desiredX = 0;
181428d7b3dSmrg			crtc->desiredY = 0;
182428d7b3dSmrg			crtc->enabled = TRUE;
183428d7b3dSmrg		}
184428d7b3dSmrg	}
185428d7b3dSmrg
186428d7b3dSmrg	xf86DisableUnusedFunctions(scrn);
187428d7b3dSmrg#ifdef RANDR_12_INTERFACE
188428d7b3dSmrg	if (get_root_window(scrn->pScreen))
189428d7b3dSmrg		xf86RandR12TellChanged(scrn->pScreen);
190428d7b3dSmrg#endif
191428d7b3dSmrg}
192428d7b3dSmrg
193428d7b3dSmrgstatic Bool sna_set_desired_mode(struct sna *sna)
194428d7b3dSmrg{
195428d7b3dSmrg	ScrnInfoPtr scrn = sna->scrn;
196428d7b3dSmrg
197428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
198428d7b3dSmrg
199428d7b3dSmrg	if (!xf86SetDesiredModes(scrn)) {
200428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
201428d7b3dSmrg			   "failed to restore desired modes on VT switch\n");
202428d7b3dSmrg		sna_set_fallback_mode(scrn);
203428d7b3dSmrg	}
204428d7b3dSmrg
205428d7b3dSmrg	sna_mode_check(sna);
206428d7b3dSmrg	return TRUE;
207428d7b3dSmrg}
208428d7b3dSmrg
209428d7b3dSmrg/**
210428d7b3dSmrg * Adjust the screen pixmap for the current location of the front buffer.
211428d7b3dSmrg * This is done at EnterVT when buffers are bound as long as the resources
212428d7b3dSmrg * have already been created, but the first EnterVT happens before
213428d7b3dSmrg * CreateScreenResources.
214428d7b3dSmrg */
215428d7b3dSmrgstatic Bool sna_create_screen_resources(ScreenPtr screen)
216428d7b3dSmrg{
217428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
218428d7b3dSmrg	PixmapPtr new_front;
219428d7b3dSmrg	unsigned hint;
220428d7b3dSmrg
221428d7b3dSmrg	DBG(("%s(%dx%d@%d)\n", __FUNCTION__,
222428d7b3dSmrg	     screen->width, screen->height, screen->rootDepth));
223428d7b3dSmrg
224428d7b3dSmrg	assert(sna->scrn == xf86ScreenToScrn(screen));
225428d7b3dSmrg	assert(sna->scrn->pScreen == screen);
226428d7b3dSmrg
227428d7b3dSmrg	/* free the data used during miInitScreen */
228428d7b3dSmrg	free(screen->devPrivate);
229428d7b3dSmrg	screen->devPrivate = NULL;
230428d7b3dSmrg
231428d7b3dSmrg	sna_accel_create(sna);
232428d7b3dSmrg
233428d7b3dSmrg	hint = SNA_CREATE_FB;
234428d7b3dSmrg	if (sna->flags & SNA_IS_HOSTED)
235428d7b3dSmrg		hint = 0;
236428d7b3dSmrg
237428d7b3dSmrg	new_front = screen->CreatePixmap(screen,
238428d7b3dSmrg					 screen->width,
239428d7b3dSmrg					 screen->height,
240428d7b3dSmrg					 screen->rootDepth,
241428d7b3dSmrg					 hint);
242428d7b3dSmrg	if (!new_front) {
243428d7b3dSmrg		xf86DrvMsg(screen->myNum, X_ERROR,
244428d7b3dSmrg			   "[intel] Unable to create front buffer %dx%d at depth %d\n",
245428d7b3dSmrg			   screen->width,
246428d7b3dSmrg			   screen->height,
247428d7b3dSmrg			   screen->rootDepth);
248428d7b3dSmrg
249428d7b3dSmrg		return FALSE;
250428d7b3dSmrg	}
251428d7b3dSmrg
252428d7b3dSmrg	/* Prefer to use the GPU for rendering into the eventual scanout
253428d7b3dSmrg	 * bo so that we do not unduly stall when it is time to attach
254428d7b3dSmrg	 * it to the CRTCs.
255428d7b3dSmrg	 */
256428d7b3dSmrg	(void)sna_pixmap_force_to_gpu(new_front, MOVE_READ | __MOVE_SCANOUT);
257428d7b3dSmrg
258428d7b3dSmrg	screen->SetScreenPixmap(new_front);
259428d7b3dSmrg	assert(screen->GetScreenPixmap(screen) == new_front);
260428d7b3dSmrg	assert(sna->front == new_front);
261428d7b3dSmrg	screen->DestroyPixmap(new_front); /* transfer ownership to screen */
262428d7b3dSmrg
263428d7b3dSmrg	sna_mode_set_primary(sna);
264428d7b3dSmrg
265428d7b3dSmrg	/* Try to become master and copy the current fbcon before the
266428d7b3dSmrg	 * actual VT switch. If we fail here, we will try to reset the
267428d7b3dSmrg	 * mode in the eventual VT switch. This can fail if systemd has
268428d7b3dSmrg	 * already revoked our KMS privileges, so just carry on regardless,
269428d7b3dSmrg	 * and hope that everything is sorted after the VT switch.
270428d7b3dSmrg	 */
271428d7b3dSmrg	if (intel_get_master(sna->dev) == 0) {
272428d7b3dSmrg		/* Only preserve the fbcon, not any subsequent server regens */
273428d7b3dSmrg		if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
274428d7b3dSmrg			sna_copy_fbcon(sna);
275428d7b3dSmrg
276428d7b3dSmrg		(void)sna_set_desired_mode(sna);
277428d7b3dSmrg	}
278428d7b3dSmrg
279428d7b3dSmrg	return TRUE;
280428d7b3dSmrg}
281428d7b3dSmrg
282428d7b3dSmrgstatic Bool sna_save_screen(ScreenPtr screen, int mode)
283428d7b3dSmrg{
284428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
285428d7b3dSmrg
286428d7b3dSmrg	DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
287428d7b3dSmrg	if (!scrn->vtSema)
288428d7b3dSmrg		return FALSE;
289428d7b3dSmrg
290428d7b3dSmrg	xf86SaveScreen(screen, mode);
291428d7b3dSmrg	sna_crtc_config_notify(screen);
292428d7b3dSmrg	return TRUE;
293428d7b3dSmrg}
294428d7b3dSmrg
295428d7b3dSmrgstatic void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
296428d7b3dSmrg{
297428d7b3dSmrg	DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
298428d7b3dSmrg	if (!scrn->vtSema)
299428d7b3dSmrg		return;
300428d7b3dSmrg
301428d7b3dSmrg	xf86DPMSSet(scrn, mode, flags);
302428d7b3dSmrg	sna_crtc_config_notify(xf86ScrnToScreen(scrn));
303428d7b3dSmrg}
304428d7b3dSmrg
305428d7b3dSmrgstatic void sna_selftest(void)
306428d7b3dSmrg{
307428d7b3dSmrg	sna_damage_selftest();
308428d7b3dSmrg}
309428d7b3dSmrg
310428d7b3dSmrgstatic bool has_vsync(struct sna *sna)
311428d7b3dSmrg{
312428d7b3dSmrg	if (sna->flags & SNA_IS_HOSTED)
313428d7b3dSmrg		return false;
314428d7b3dSmrg
315428d7b3dSmrg	return true;
316428d7b3dSmrg}
317428d7b3dSmrg
318428d7b3dSmrgstatic void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
319428d7b3dSmrg{
320428d7b3dSmrg#if HAS_PIXMAP_SHARING && defined(DRM_CAP_PRIME)
321428d7b3dSmrg	uint64_t value;
322428d7b3dSmrg
323428d7b3dSmrg	scrn->capabilities = 0;
324428d7b3dSmrg	if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0) {
325428d7b3dSmrg		if (value & DRM_PRIME_CAP_EXPORT)
326428d7b3dSmrg			scrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SinkOffload;
327428d7b3dSmrg		if (value & DRM_PRIME_CAP_IMPORT)
328428d7b3dSmrg			scrn->capabilities |= RR_Capability_SinkOutput;
329428d7b3dSmrg	}
330428d7b3dSmrg#endif
331428d7b3dSmrg}
332428d7b3dSmrg
333428d7b3dSmrgstatic int
334428d7b3dSmrgnamecmp(const char *s1, const char *s2)
335428d7b3dSmrg{
336428d7b3dSmrg	char c1, c2;
337428d7b3dSmrg
338428d7b3dSmrg	if (!s1 || *s1 == 0) {
339428d7b3dSmrg		if (!s2 || *s2 == 0)
340428d7b3dSmrg			return 0;
341428d7b3dSmrg		else
342428d7b3dSmrg			return 1;
343428d7b3dSmrg	}
344428d7b3dSmrg
345428d7b3dSmrg	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
346428d7b3dSmrg		s1++;
347428d7b3dSmrg
348428d7b3dSmrg	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
349428d7b3dSmrg		s2++;
350428d7b3dSmrg
351428d7b3dSmrg	c1 = isupper(*s1) ? tolower(*s1) : *s1;
352428d7b3dSmrg	c2 = isupper(*s2) ? tolower(*s2) : *s2;
353428d7b3dSmrg	while (c1 == c2) {
354428d7b3dSmrg		if (c1 == '\0')
355428d7b3dSmrg			return 0;
356428d7b3dSmrg
357428d7b3dSmrg		s1++;
358428d7b3dSmrg		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
359428d7b3dSmrg			s1++;
360428d7b3dSmrg
361428d7b3dSmrg		s2++;
362428d7b3dSmrg		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
363428d7b3dSmrg			s2++;
364428d7b3dSmrg
365428d7b3dSmrg		c1 = isupper(*s1) ? tolower(*s1) : *s1;
366428d7b3dSmrg		c2 = isupper(*s2) ? tolower(*s2) : *s2;
367428d7b3dSmrg	}
368428d7b3dSmrg
369428d7b3dSmrg	return c1 - c2;
370428d7b3dSmrg}
371428d7b3dSmrg
372428d7b3dSmrgstatic Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
373428d7b3dSmrg{
374428d7b3dSmrg	const char *str = xf86GetOptValString(sna->Options, id);
375428d7b3dSmrg
376428d7b3dSmrg	if (str == NULL)
377428d7b3dSmrg		return val;
378428d7b3dSmrg
379428d7b3dSmrg	if (*str == '\0')
380428d7b3dSmrg		return TRUE;
381428d7b3dSmrg
382428d7b3dSmrg	if (namecmp(str, "1") == 0)
383428d7b3dSmrg		return TRUE;
384428d7b3dSmrg	if (namecmp(str, "on") == 0)
385428d7b3dSmrg		return TRUE;
386428d7b3dSmrg	if (namecmp(str, "true") == 0)
387428d7b3dSmrg		return TRUE;
388428d7b3dSmrg	if (namecmp(str, "yes") == 0)
389428d7b3dSmrg		return TRUE;
390428d7b3dSmrg
391428d7b3dSmrg	if (namecmp(str, "0") == 0)
392428d7b3dSmrg		return FALSE;
393428d7b3dSmrg	if (namecmp(str, "off") == 0)
394428d7b3dSmrg		return FALSE;
395428d7b3dSmrg	if (namecmp(str, "false") == 0)
396428d7b3dSmrg		return FALSE;
397428d7b3dSmrg	if (namecmp(str, "no") == 0)
398428d7b3dSmrg		return FALSE;
399428d7b3dSmrg
400428d7b3dSmrg	return val;
401428d7b3dSmrg}
402428d7b3dSmrg
403428d7b3dSmrgstatic unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val)
404428d7b3dSmrg{
405428d7b3dSmrg	const char *str = xf86GetOptValString(sna->Options, id);
406428d7b3dSmrg	unsigned v;
407428d7b3dSmrg
408428d7b3dSmrg	if (str == NULL || *str == '\0')
409428d7b3dSmrg		return val;
410428d7b3dSmrg
411428d7b3dSmrg	if (namecmp(str, "on") == 0)
412428d7b3dSmrg		return val;
413428d7b3dSmrg	if (namecmp(str, "true") == 0)
414428d7b3dSmrg		return val;
415428d7b3dSmrg	if (namecmp(str, "yes") == 0)
416428d7b3dSmrg		return val;
417428d7b3dSmrg
418428d7b3dSmrg	if (namecmp(str, "0") == 0)
419428d7b3dSmrg		return 0;
420428d7b3dSmrg	if (namecmp(str, "off") == 0)
421428d7b3dSmrg		return 0;
422428d7b3dSmrg	if (namecmp(str, "false") == 0)
423428d7b3dSmrg		return 0;
424428d7b3dSmrg	if (namecmp(str, "no") == 0)
425428d7b3dSmrg		return 0;
426428d7b3dSmrg
427428d7b3dSmrg	v = atoi(str);
428428d7b3dSmrg	if (v)
429428d7b3dSmrg		return v;
430428d7b3dSmrg
431428d7b3dSmrg	return val;
432428d7b3dSmrg}
433428d7b3dSmrg
434428d7b3dSmrgstatic Bool fb_supports_depth(int fd, int depth)
435428d7b3dSmrg{
436428d7b3dSmrg	struct drm_i915_gem_create create;
437428d7b3dSmrg	struct drm_mode_fb_cmd fb;
438428d7b3dSmrg	struct drm_mode_card_res res;
439428d7b3dSmrg	Bool ret;
440428d7b3dSmrg
441428d7b3dSmrg	memset(&res, 0, sizeof(res));
442428d7b3dSmrg	(void)drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
443428d7b3dSmrg	if (res.count_crtcs == 0)
444428d7b3dSmrg		return TRUE;
445428d7b3dSmrg
446428d7b3dSmrg	VG_CLEAR(create);
447428d7b3dSmrg	create.handle = 0;
448428d7b3dSmrg	create.size = 4096;
449428d7b3dSmrg	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create))
450428d7b3dSmrg		return FALSE;
451428d7b3dSmrg
452428d7b3dSmrg	VG_CLEAR(fb);
453428d7b3dSmrg	fb.width = 64;
454428d7b3dSmrg	fb.height = 16;
455428d7b3dSmrg	fb.pitch = 256;
456428d7b3dSmrg	fb.bpp = depth <= 8 ? 8 : depth <= 16 ? 16 : 32;
457428d7b3dSmrg	fb.depth = depth;
458428d7b3dSmrg	fb.handle = create.handle;
459428d7b3dSmrg
460428d7b3dSmrg	ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB, &fb) == 0;
461428d7b3dSmrg	drmModeRmFB(fd, fb.fb_id);
462428d7b3dSmrg
463428d7b3dSmrg	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
464428d7b3dSmrg
465428d7b3dSmrg	return ret;
466428d7b3dSmrg}
467428d7b3dSmrg
468428d7b3dSmrgstatic void setup_dri(struct sna *sna)
469428d7b3dSmrg{
470428d7b3dSmrg	unsigned level;
471428d7b3dSmrg
472428d7b3dSmrg	sna->dri2.available = false;
473428d7b3dSmrg	sna->dri3.available = false;
474428d7b3dSmrg
475428d7b3dSmrg	level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0);
476428d7b3dSmrg#if HAVE_DRI3
477428d7b3dSmrg	if (level >= 3)
478428d7b3dSmrg		sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
479428d7b3dSmrg#endif
480428d7b3dSmrg#if HAVE_DRI2
481428d7b3dSmrg	if (level >= 2)
482428d7b3dSmrg		sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
483428d7b3dSmrg#endif
484428d7b3dSmrg}
485428d7b3dSmrg
486428d7b3dSmrgstatic bool enable_tear_free(struct sna *sna)
487428d7b3dSmrg{
488428d7b3dSmrg	if (sna->flags & SNA_LINEAR_FB)
489428d7b3dSmrg		return false;
490428d7b3dSmrg
491428d7b3dSmrg	/* Under certain conditions, we should enable TearFree by default,
492428d7b3dSmrg	 * for example when the hardware requires pageflipping to run within
493428d7b3dSmrg	 * its power/performance budget.
494428d7b3dSmrg	 */
495428d7b3dSmrg	if (sna_mode_wants_tear_free(sna))
496428d7b3dSmrg		return true;
497428d7b3dSmrg
498428d7b3dSmrg	return ENABLE_TEAR_FREE;
499428d7b3dSmrg}
500428d7b3dSmrg
501428d7b3dSmrgstatic void setup_tear_free(struct sna *sna)
502428d7b3dSmrg{
503428d7b3dSmrg	MessageType from;
504428d7b3dSmrg	Bool enable;
505428d7b3dSmrg
506428d7b3dSmrg	if (sna->flags & SNA_LINEAR_FB)
507428d7b3dSmrg		return;
508428d7b3dSmrg
509428d7b3dSmrg	if ((sna->flags & SNA_HAS_FLIP) == 0) {
510428d7b3dSmrg		from = X_PROBED;
511428d7b3dSmrg		goto done;
512428d7b3dSmrg	}
513428d7b3dSmrg
514428d7b3dSmrg	if (!xf86GetOptValBool(sna->Options, OPTION_TEAR_FREE, &enable)) {
515428d7b3dSmrg		enable = enable_tear_free(sna);
516428d7b3dSmrg		from = X_DEFAULT;
517428d7b3dSmrg	} else
518428d7b3dSmrg		from = X_CONFIG;
519428d7b3dSmrg
520428d7b3dSmrg	if (enable)
521428d7b3dSmrg		sna->flags |= SNA_TEAR_FREE;
522428d7b3dSmrg
523428d7b3dSmrgdone:
524428d7b3dSmrg	xf86DrvMsg(sna->scrn->scrnIndex, from, "TearFree %sabled\n",
525428d7b3dSmrg		   sna->flags & SNA_TEAR_FREE ? "en" : "dis");
526428d7b3dSmrg}
527428d7b3dSmrg
528428d7b3dSmrg/**
529428d7b3dSmrg * This is called before ScreenInit to do any require probing of screen
530428d7b3dSmrg * configuration.
531428d7b3dSmrg *
532428d7b3dSmrg * This code generally covers probing, module loading, option handling
533428d7b3dSmrg * card mapping, and RandR setup.
534428d7b3dSmrg *
535428d7b3dSmrg * Since xf86InitialConfiguration ends up requiring that we set video modes
536428d7b3dSmrg * in order to detect configuration, we end up having to do a lot of driver
537428d7b3dSmrg * setup (talking to the DRM, mapping the device, etc.) in this function.
538428d7b3dSmrg * As a result, we want to set up that server initialization once rather
539428d7b3dSmrg * that doing it per generation.
540428d7b3dSmrg */
541428d7b3dSmrgstatic Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
542428d7b3dSmrg{
543428d7b3dSmrg	struct sna *sna;
544428d7b3dSmrg	char buf[1024];
545428d7b3dSmrg	rgb defaultWeight = { 0, 0, 0 };
546428d7b3dSmrg	EntityInfoPtr pEnt;
547428d7b3dSmrg	Gamma zeros = { 0.0, 0.0, 0.0 };
548428d7b3dSmrg	int fd;
549428d7b3dSmrg
550428d7b3dSmrg	DBG(("%s flags=%x, numEntities=%d\n",
551428d7b3dSmrg	     __FUNCTION__, probe, scrn->numEntities));
552428d7b3dSmrg
553428d7b3dSmrg	if (scrn->numEntities != 1)
554428d7b3dSmrg		return FALSE;
555428d7b3dSmrg
556428d7b3dSmrg	pEnt = xf86GetEntityInfo(scrn->entityList[0]);
557428d7b3dSmrg	if (pEnt == NULL) {
558428d7b3dSmrg		ERR(("%s: no EntityInfo found for scrn\n", __FUNCTION__));
559428d7b3dSmrg		return FALSE;
560428d7b3dSmrg	}
561428d7b3dSmrg
562428d7b3dSmrg	if (pEnt->location.type != BUS_PCI
563428d7b3dSmrg#ifdef XSERVER_PLATFORM_BUS
564428d7b3dSmrg	    && pEnt->location.type != BUS_PLATFORM
565428d7b3dSmrg#endif
566428d7b3dSmrg		) {
567428d7b3dSmrg		ERR(("%s: invalid EntityInfo found for scrn, location=%d\n", __FUNCTION__, pEnt->location.type));
568428d7b3dSmrg		return FALSE;
569428d7b3dSmrg	}
570428d7b3dSmrg
571428d7b3dSmrg	if (probe & PROBE_DETECT)
572428d7b3dSmrg		return TRUE;
573428d7b3dSmrg
574428d7b3dSmrg	sna_selftest();
575428d7b3dSmrg
576428d7b3dSmrg	probe = 0;
577428d7b3dSmrg	if (((uintptr_t)scrn->driverPrivate) & 3) {
578428d7b3dSmrg		if (posix_memalign((void **)&sna, 4096, sizeof(*sna)))
579428d7b3dSmrg			return FALSE;
580428d7b3dSmrg
581428d7b3dSmrg		memset(sna, 0, sizeof(*sna)); /* should be unnecessary */
582428d7b3dSmrg		probe = (uintptr_t)scrn->driverPrivate & 1;
583428d7b3dSmrg		sna->info = (void *)((uintptr_t)scrn->driverPrivate & ~3);
584428d7b3dSmrg		scrn->driverPrivate = sna;
585428d7b3dSmrg
586428d7b3dSmrg		sna->cpu_features = sna_cpu_detect();
587428d7b3dSmrg		sna->acpi.fd = sna_acpi_open();
588428d7b3dSmrg	}
589428d7b3dSmrg	sna = to_sna(scrn);
590428d7b3dSmrg	sna->scrn = scrn;
591428d7b3dSmrg	sna->pEnt = pEnt;
592428d7b3dSmrg	sna->flags = probe;
593428d7b3dSmrg
594428d7b3dSmrg	scrn->displayWidth = 640;	/* default it */
595428d7b3dSmrg
596428d7b3dSmrg	scrn->monitor = scrn->confScreen->monitor;
597428d7b3dSmrg	scrn->progClock = TRUE;
598428d7b3dSmrg	scrn->rgbBits = 8;
599428d7b3dSmrg
600428d7b3dSmrg	sna->dev = intel_get_device(scrn, &fd);
601428d7b3dSmrg	if (sna->dev == NULL) {
602428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
603428d7b3dSmrg			   "Failed to claim DRM device.\n");
604428d7b3dSmrg		goto cleanup;
605428d7b3dSmrg	}
606428d7b3dSmrg
607428d7b3dSmrg	/* Sanity check */
608428d7b3dSmrg	if (hosted() && (sna->flags & SNA_IS_HOSTED) == 0) {
609428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
610428d7b3dSmrg			   "Failed to setup hosted device.\n");
611428d7b3dSmrg		goto cleanup;
612428d7b3dSmrg	}
613428d7b3dSmrg
614428d7b3dSmrg	intel_detect_chipset(scrn, sna->dev);
615428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
616428d7b3dSmrg		   sna_cpu_features_to_string(sna->cpu_features, buf));
617428d7b3dSmrg
618428d7b3dSmrg	if (!xf86SetDepthBpp(scrn, 24, 0, 0,
619428d7b3dSmrg			     Support32bppFb |
620428d7b3dSmrg			     SupportConvert24to32 | PreferConvert24to32))
621428d7b3dSmrg		goto cleanup;
622428d7b3dSmrg
623428d7b3dSmrg	switch (scrn->depth) {
624428d7b3dSmrg	case 8:
625428d7b3dSmrg	case 15:
626428d7b3dSmrg	case 16:
627428d7b3dSmrg	case 24:
628428d7b3dSmrg	case 30:
629428d7b3dSmrg		if ((sna->flags & SNA_IS_HOSTED) ||
630428d7b3dSmrg		    fb_supports_depth(fd, scrn->depth))
631428d7b3dSmrg			break;
632428d7b3dSmrg	default:
633428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
634428d7b3dSmrg			   "Given depth (%d) is not supported by the Intel driver and this chipset.\n",
635428d7b3dSmrg			   scrn->depth);
636428d7b3dSmrg		goto cleanup;
637428d7b3dSmrg	}
638428d7b3dSmrg	xf86PrintDepthBpp(scrn);
639428d7b3dSmrg
640428d7b3dSmrg	if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
641428d7b3dSmrg		goto cleanup;
642428d7b3dSmrg	if (!xf86SetDefaultVisual(scrn, -1))
643428d7b3dSmrg		goto cleanup;
644428d7b3dSmrg
645428d7b3dSmrg	sna->Options = intel_options_get(scrn);
646428d7b3dSmrg	if (sna->Options == NULL)
647428d7b3dSmrg		goto cleanup;
648428d7b3dSmrg
649428d7b3dSmrg	sna_setup_capabilities(scrn, fd);
650428d7b3dSmrg
651428d7b3dSmrg	kgem_init(&sna->kgem, fd,
652428d7b3dSmrg		  xf86GetPciInfoForEntity(pEnt->index),
653428d7b3dSmrg		  sna->info->gen);
654428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
655428d7b3dSmrg	    !sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
656428d7b3dSmrg		xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
657428d7b3dSmrg			   "Disabling hardware acceleration.\n");
658428d7b3dSmrg		sna->kgem.wedged = true;
659428d7b3dSmrg	}
660428d7b3dSmrg
661428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
662428d7b3dSmrg		sna->flags |= SNA_LINEAR_FB;
663428d7b3dSmrg
664428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE))
665428d7b3dSmrg		sna->flags |= SNA_REMOVE_OUTPUTS;
666428d7b3dSmrg
667428d7b3dSmrg	if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
668428d7b3dSmrg		sna->flags |= SNA_NO_WAIT;
669428d7b3dSmrg	DBG(("%s: swapbuffer wait? %s\n", __FUNCTION__, sna->flags & SNA_NO_WAIT ? "disabled" : "enabled"));
670428d7b3dSmrg
671428d7b3dSmrg	if (!has_vsync(sna) ||
672428d7b3dSmrg	    !xf86ReturnOptValBool(sna->Options, OPTION_VSYNC, TRUE))
673428d7b3dSmrg		sna->flags |= SNA_NO_VSYNC;
674428d7b3dSmrg	DBG(("%s: vsync? %s\n", __FUNCTION__, sna->flags & SNA_NO_VSYNC ? "disabled" : "enabled"));
675428d7b3dSmrg
676428d7b3dSmrg	if (sna->flags & SNA_IS_HOSTED ||
677428d7b3dSmrg	    !xf86ReturnOptValBool(sna->Options, OPTION_PAGEFLIP, TRUE))
678428d7b3dSmrg		sna->flags |= SNA_NO_FLIP;
679428d7b3dSmrg	DBG(("%s: page flips? %s\n", __FUNCTION__, sna->flags & SNA_NO_FLIP ? "disabled" : "enabled"));
680428d7b3dSmrg
681428d7b3dSmrg	if ((sna->flags & (SNA_NO_VSYNC | SNA_NO_FLIP | SNA_NO_WAIT)) == 0 &&
682428d7b3dSmrg	    xf86ReturnOptValBool(sna->Options, OPTION_TRIPLE_BUFFER, TRUE))
683428d7b3dSmrg		sna->flags |= SNA_TRIPLE_BUFFER;
684428d7b3dSmrg	DBG(("%s: triple buffer? %s\n", __FUNCTION__, sna->flags & SNA_TRIPLE_BUFFER ? "enabled" : "disabled"));
685428d7b3dSmrg
686428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_CRTC_PIXMAPS, FALSE)) {
687428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Forcing per-crtc-pixmaps.\n");
688428d7b3dSmrg		sna->flags |= SNA_FORCE_SHADOW;
689428d7b3dSmrg	}
690428d7b3dSmrg
691428d7b3dSmrg	if (!sna_mode_pre_init(scrn, sna)) {
692428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
693428d7b3dSmrg			   "No outputs and no modes.\n");
694428d7b3dSmrg		goto cleanup;
695428d7b3dSmrg	}
696428d7b3dSmrg	scrn->currentMode = scrn->modes;
697428d7b3dSmrg
698428d7b3dSmrg	setup_tear_free(sna);
699428d7b3dSmrg
700428d7b3dSmrg	xf86SetGamma(scrn, zeros);
701428d7b3dSmrg	xf86SetDpi(scrn, 0, 0);
702428d7b3dSmrg
703428d7b3dSmrg	setup_dri(sna);
704428d7b3dSmrg
705428d7b3dSmrg	sna->present.available = false;
706428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_PRESENT, TRUE)) {
707428d7b3dSmrg#if HAVE_PRESENT
708428d7b3dSmrg		sna->present.available = !!xf86LoadSubModule(scrn, "present");
709428d7b3dSmrg#endif
710428d7b3dSmrg	}
711428d7b3dSmrg
712428d7b3dSmrg	sna_acpi_init(sna);
713428d7b3dSmrg
714428d7b3dSmrg	return TRUE;
715428d7b3dSmrg
716428d7b3dSmrgcleanup:
717428d7b3dSmrg	scrn->driverPrivate = (void *)((uintptr_t)sna->info | (sna->flags & SNA_IS_SLAVED) | 2);
718428d7b3dSmrg	if (sna->dev)
719428d7b3dSmrg		intel_put_device(sna->dev);
720428d7b3dSmrg	free(sna);
721428d7b3dSmrg	return FALSE;
722428d7b3dSmrg}
723428d7b3dSmrg
724428d7b3dSmrgstatic bool has_shadow(struct sna *sna)
725428d7b3dSmrg{
726428d7b3dSmrg	if (!sna->mode.shadow_damage)
727428d7b3dSmrg		return false;
728428d7b3dSmrg
729428d7b3dSmrg	if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
730428d7b3dSmrg		return false;
731428d7b3dSmrg
732428d7b3dSmrg	return sna->mode.flip_active == 0;
733428d7b3dSmrg}
734428d7b3dSmrg
735428d7b3dSmrgstatic void
736428d7b3dSmrgsna_block_handler(BLOCKHANDLER_ARGS_DECL)
737428d7b3dSmrg{
738428d7b3dSmrg#ifndef XF86_SCRN_INTERFACE
739428d7b3dSmrg	struct sna *sna = to_sna(xf86Screens[arg]);
740428d7b3dSmrg#else
741428d7b3dSmrg	struct sna *sna = to_sna_from_screen(arg);
742428d7b3dSmrg#endif
743428d7b3dSmrg#if ABI_VIDEODRV_VERSION < SET_ABI_VERSION(23, 0)
744428d7b3dSmrg	struct timeval **tv = timeout;
745428d7b3dSmrg
746428d7b3dSmrg	DBG(("%s (tv=%ld.%06ld)\n", __FUNCTION__,
747428d7b3dSmrg	     *tv ? (*tv)->tv_sec : -1, *tv ? (*tv)->tv_usec : 0));
748428d7b3dSmrg#else
749428d7b3dSmrg	int *tv = timeout;
750428d7b3dSmrg
751428d7b3dSmrg	DBG(("%s (tv=%ld.%06ld)\n", __FUNCTION__,
752428d7b3dSmrg	     *tv / 1000, *tv % (1000 * 1000)));
753428d7b3dSmrg#endif
754428d7b3dSmrg
755428d7b3dSmrg	sna->BlockHandler(BLOCKHANDLER_ARGS);
756428d7b3dSmrg
757428d7b3dSmrg#if ABI_VIDEODRV_VERSION < SET_ABI_VERSION(23, 0)
758428d7b3dSmrg	if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec) || has_shadow(sna))
759428d7b3dSmrg#endif
760428d7b3dSmrg		sna_accel_block_handler(sna, tv);
761428d7b3dSmrg}
762428d7b3dSmrg
763428d7b3dSmrgstatic void
764428d7b3dSmrgsna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
765428d7b3dSmrg{
766428d7b3dSmrg#ifndef XF86_SCRN_INTERFACE
767428d7b3dSmrg	struct sna *sna = to_sna(xf86Screens[arg]);
768428d7b3dSmrg#else
769428d7b3dSmrg	struct sna *sna = to_sna_from_screen(arg);
770428d7b3dSmrg#endif
771428d7b3dSmrg
772428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
773428d7b3dSmrg
774428d7b3dSmrg	/* despite all appearances, result is just a signed int */
775428d7b3dSmrg	if ((int)result < 0)
776428d7b3dSmrg		return;
777428d7b3dSmrg
778428d7b3dSmrg	sna_acpi_wakeup(sna);
779428d7b3dSmrg
780428d7b3dSmrg	sna->WakeupHandler(WAKEUPHANDLER_ARGS);
781428d7b3dSmrg
782428d7b3dSmrg	sna_accel_wakeup_handler(sna);
783428d7b3dSmrg
784428d7b3dSmrg	sna_mode_wakeup(sna);
785428d7b3dSmrg}
786428d7b3dSmrg
787428d7b3dSmrg#if HAVE_UDEV
788428d7b3dSmrgstatic void
789428d7b3dSmrgsna_handle_uevents(int fd, void *closure)
790428d7b3dSmrg{
791428d7b3dSmrg	struct sna *sna = closure;
792428d7b3dSmrg	struct udev_device *dev;
793428d7b3dSmrg	const char *str;
794428d7b3dSmrg	struct stat s;
795428d7b3dSmrg	dev_t udev_devnum;
796428d7b3dSmrg
797428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
798428d7b3dSmrg
799428d7b3dSmrg	dev = udev_monitor_receive_device(sna->uevent_monitor);
800428d7b3dSmrg	if (!dev)
801428d7b3dSmrg		return;
802428d7b3dSmrg
803428d7b3dSmrg	udev_devnum = udev_device_get_devnum(dev);
804428d7b3dSmrg	if (fstat(sna->kgem.fd, &s) || memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))) {
805428d7b3dSmrg		udev_device_unref(dev);
806428d7b3dSmrg		return;
807428d7b3dSmrg	}
808428d7b3dSmrg
809428d7b3dSmrg	str = udev_device_get_property_value(dev, "HOTPLUG");
810428d7b3dSmrg	if (str && atoi(str) == 1) {
811428d7b3dSmrg		ScrnInfoPtr scrn = sna->scrn;
812428d7b3dSmrg
813428d7b3dSmrg		DBG(("%s: hotplug event (vtSema?=%d)\n", __FUNCTION__, scrn->vtSema));
814428d7b3dSmrg
815428d7b3dSmrg		if (scrn->vtSema) {
816428d7b3dSmrg			sna_mode_discover(sna);
817428d7b3dSmrg			sna_mode_check(sna);
818428d7b3dSmrg			RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
819428d7b3dSmrg		} else
820428d7b3dSmrg			sna->flags |= SNA_REPROBE;
821428d7b3dSmrg	}
822428d7b3dSmrg
823428d7b3dSmrg	udev_device_unref(dev);
824428d7b3dSmrg}
825428d7b3dSmrg
826428d7b3dSmrgstatic void
827428d7b3dSmrgsna_uevent_init(struct sna *sna)
828428d7b3dSmrg{
829428d7b3dSmrg	struct udev *u;
830428d7b3dSmrg	struct udev_monitor *mon;
831428d7b3dSmrg	MessageType from = X_CONFIG;
832428d7b3dSmrg
833428d7b3dSmrg	if (sna->flags & SNA_IS_HOSTED)
834428d7b3dSmrg		return;
835428d7b3dSmrg
836428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
837428d7b3dSmrg
838428d7b3dSmrg	/* RandR will be disabled if Xinerama is active, and so generating
839428d7b3dSmrg	 * RR hotplug events is then verboten.
840428d7b3dSmrg	 */
841428d7b3dSmrg	if (!dixPrivateKeyRegistered(rrPrivKey))
842428d7b3dSmrg		goto out;
843428d7b3dSmrg
844428d7b3dSmrg	u = NULL;
845428d7b3dSmrg	if (xf86ReturnOptValBool(sna->Options, OPTION_HOTPLUG, TRUE))
846428d7b3dSmrg		u = udev_new();
847428d7b3dSmrg	if (!u)
848428d7b3dSmrg		goto out;
849428d7b3dSmrg
850428d7b3dSmrg	from = X_DEFAULT;
851428d7b3dSmrg
852428d7b3dSmrg	mon = udev_monitor_new_from_netlink(u, "udev");
853428d7b3dSmrg	if (!mon)
854428d7b3dSmrg		goto err_dev;
855428d7b3dSmrg
856428d7b3dSmrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0)
857428d7b3dSmrg		goto err_monitor;
858428d7b3dSmrg
859428d7b3dSmrg	if (udev_monitor_enable_receiving(mon) < 0)
860428d7b3dSmrg		goto err_monitor;
861428d7b3dSmrg
862428d7b3dSmrg	sna->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
863428d7b3dSmrg						    sna_handle_uevents, sna);
864428d7b3dSmrg	if (!sna->uevent_handler)
865428d7b3dSmrg		goto err_monitor;
866428d7b3dSmrg
867428d7b3dSmrg	sna->uevent_monitor = mon;
868428d7b3dSmrgout:
869428d7b3dSmrg	xf86DrvMsg(sna->scrn->scrnIndex, from, "display hotplug detection %s\n",
870428d7b3dSmrg		   sna->uevent_monitor ? "enabled" : "disabled");
871428d7b3dSmrg	return;
872428d7b3dSmrg
873428d7b3dSmrgerr_monitor:
874428d7b3dSmrg	udev_monitor_unref(mon);
875428d7b3dSmrgerr_dev:
876428d7b3dSmrg	udev_unref(u);
877428d7b3dSmrg	goto out;
878428d7b3dSmrg}
879428d7b3dSmrg
880428d7b3dSmrgstatic bool sna_uevent_poll(struct sna *sna)
881428d7b3dSmrg{
882428d7b3dSmrg	struct pollfd pfd;
883428d7b3dSmrg
884428d7b3dSmrg	if (sna->uevent_monitor == NULL)
885428d7b3dSmrg		return false;
886428d7b3dSmrg
887428d7b3dSmrg	pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
888428d7b3dSmrg	pfd.events = POLLIN;
889428d7b3dSmrg
890428d7b3dSmrg	while (poll(&pfd, 1, 0) > 0)
891428d7b3dSmrg		sna_handle_uevents(pfd.fd, sna);
892428d7b3dSmrg
893428d7b3dSmrg	return true;
894428d7b3dSmrg}
895428d7b3dSmrg
896428d7b3dSmrgstatic void
897428d7b3dSmrgsna_uevent_fini(struct sna *sna)
898428d7b3dSmrg{
899428d7b3dSmrg	struct udev *u;
900428d7b3dSmrg
901428d7b3dSmrg	if (sna->uevent_handler == NULL)
902428d7b3dSmrg		return;
903428d7b3dSmrg
904428d7b3dSmrg	xf86RemoveGeneralHandler(sna->uevent_handler);
905428d7b3dSmrg
906428d7b3dSmrg	u = udev_monitor_get_udev(sna->uevent_monitor);
907428d7b3dSmrg	udev_monitor_unref(sna->uevent_monitor);
908428d7b3dSmrg	udev_unref(u);
909428d7b3dSmrg
910428d7b3dSmrg	sna->uevent_handler = NULL;
911428d7b3dSmrg	sna->uevent_monitor = NULL;
912428d7b3dSmrg
913428d7b3dSmrg	DBG(("%s: removed uvent handler\n", __FUNCTION__));
914428d7b3dSmrg}
915428d7b3dSmrg#else
916428d7b3dSmrgstatic void sna_uevent_init(struct sna *sna) { }
917428d7b3dSmrgstatic bool sna_uevent_poll(struct sna *sna) { return false; }
918428d7b3dSmrgstatic void sna_uevent_fini(struct sna *sna) { }
919428d7b3dSmrg#endif /* HAVE_UDEV */
920428d7b3dSmrg
921428d7b3dSmrgstatic Bool
922428d7b3dSmrgsna_randr_getinfo(ScreenPtr screen, Rotation *rotations)
923428d7b3dSmrg{
924428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
925428d7b3dSmrg
926428d7b3dSmrg	if (!sna_uevent_poll(sna))
927428d7b3dSmrg		sna_mode_discover(sna);
928428d7b3dSmrg
929428d7b3dSmrg	return sna->mode.rrGetInfo(screen, rotations);
930428d7b3dSmrg}
931428d7b3dSmrg
932428d7b3dSmrgstatic void sna_leave_vt(VT_FUNC_ARGS_DECL)
933428d7b3dSmrg{
934428d7b3dSmrg	SCRN_INFO_PTR(arg);
935428d7b3dSmrg	struct sna *sna = to_sna(scrn);
936428d7b3dSmrg
937428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
938428d7b3dSmrg
939428d7b3dSmrg	sna_accel_leave(sna);
940428d7b3dSmrg	sna_mode_reset(sna);
941428d7b3dSmrg
942428d7b3dSmrg	if (intel_put_master(sna->dev))
943428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
944428d7b3dSmrg			   "drmDropMaster failed: %s\n", strerror(errno));
945428d7b3dSmrg}
946428d7b3dSmrg
947428d7b3dSmrgstatic Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
948428d7b3dSmrg{
949428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
950428d7b3dSmrg	struct sna *sna = to_sna(scrn);
951428d7b3dSmrg
952428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
953428d7b3dSmrg
954428d7b3dSmrg	/* XXX Note that we will leak kernel resources if !vtSema */
955428d7b3dSmrg
956428d7b3dSmrg	sna_uevent_fini(sna);
957428d7b3dSmrg	sna_mode_close(sna);
958428d7b3dSmrg
959428d7b3dSmrg	if (sna->present.open) {
960428d7b3dSmrg		sna_present_close(sna, screen);
961428d7b3dSmrg		sna->present.open = false;
962428d7b3dSmrg	}
963428d7b3dSmrg
964428d7b3dSmrg	if (sna->dri3.open) {
965428d7b3dSmrg		sna_dri3_close(sna, screen);
966428d7b3dSmrg		sna->dri3.open = false;
967428d7b3dSmrg	}
968428d7b3dSmrg
969428d7b3dSmrg	if (sna->dri2.open) {
970428d7b3dSmrg		sna_dri2_close(sna, screen);
971428d7b3dSmrg		sna->dri2.open = false;
972428d7b3dSmrg	}
973428d7b3dSmrg
974428d7b3dSmrg	if (sna->front) {
975428d7b3dSmrg		screen->DestroyPixmap(sna->front);
976428d7b3dSmrg		sna->front = NULL;
977428d7b3dSmrg	}
978428d7b3dSmrg
979428d7b3dSmrg	if (scrn->vtSema) {
980428d7b3dSmrg		intel_put_master(sna->dev);
981428d7b3dSmrg		scrn->vtSema = FALSE;
982428d7b3dSmrg	}
983428d7b3dSmrg
984428d7b3dSmrg	return sna->CloseScreen(CLOSE_SCREEN_ARGS);
985428d7b3dSmrg}
986428d7b3dSmrg
987428d7b3dSmrgstatic Bool sna_late_close_screen(CLOSE_SCREEN_ARGS_DECL)
988428d7b3dSmrg{
989428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
990428d7b3dSmrg	DepthPtr depths;
991428d7b3dSmrg	int d;
992428d7b3dSmrg
993428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
994428d7b3dSmrg
995428d7b3dSmrg	sna_accel_close(sna);
996428d7b3dSmrg	sna_video_close(sna);
997428d7b3dSmrg
998428d7b3dSmrg	depths = screen->allowedDepths;
999428d7b3dSmrg	for (d = 0; d < screen->numDepths; d++)
1000428d7b3dSmrg		free(depths[d].vids);
1001428d7b3dSmrg	free(depths);
1002428d7b3dSmrg
1003428d7b3dSmrg	free(screen->visuals);
1004428d7b3dSmrg
1005428d7b3dSmrg	return TRUE;
1006428d7b3dSmrg}
1007428d7b3dSmrg
1008428d7b3dSmrgstatic Bool
1009428d7b3dSmrgsna_register_all_privates(void)
1010428d7b3dSmrg{
1011428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY
1012428d7b3dSmrg	if (!dixRegisterPrivateKey(&sna_pixmap_key, PRIVATE_PIXMAP,
1013428d7b3dSmrg				   3*sizeof(void *)))
1014428d7b3dSmrg		return FALSE;
1015428d7b3dSmrg
1016428d7b3dSmrg	if (!dixRegisterPrivateKey(&sna_gc_key, PRIVATE_GC,
1017428d7b3dSmrg				   sizeof(FbGCPrivate)))
1018428d7b3dSmrg		return FALSE;
1019428d7b3dSmrg
1020428d7b3dSmrg	if (!dixRegisterPrivateKey(&sna_glyph_key, PRIVATE_GLYPH,
1021428d7b3dSmrg				   sizeof(struct sna_glyph)))
1022428d7b3dSmrg		return FALSE;
1023428d7b3dSmrg
1024428d7b3dSmrg	if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
1025428d7b3dSmrg				   3*sizeof(void *)))
1026428d7b3dSmrg		return FALSE;
1027428d7b3dSmrg
1028428d7b3dSmrg	if (!dixRegisterPrivateKey(&sna_client_key, PRIVATE_CLIENT,
1029428d7b3dSmrg				   sizeof(struct sna_client)))
1030428d7b3dSmrg		return FALSE;
1031428d7b3dSmrg#else
1032428d7b3dSmrg	if (!dixRequestPrivate(&sna_pixmap_key, 3*sizeof(void *)))
1033428d7b3dSmrg		return FALSE;
1034428d7b3dSmrg
1035428d7b3dSmrg	if (!dixRequestPrivate(&sna_gc_key, sizeof(FbGCPrivate)))
1036428d7b3dSmrg		return FALSE;
1037428d7b3dSmrg
1038428d7b3dSmrg	if (!dixRequestPrivate(&sna_glyph_key, sizeof(struct sna_glyph)))
1039428d7b3dSmrg		return FALSE;
1040428d7b3dSmrg
1041428d7b3dSmrg	if (!dixRequestPrivate(&sna_window_key, 3*sizeof(void *)))
1042428d7b3dSmrg		return FALSE;
1043428d7b3dSmrg
1044428d7b3dSmrg	if (!dixRequestPrivate(&sna_client_key, sizeof(struct sna_client)))
1045428d7b3dSmrg		return FALSE;
1046428d7b3dSmrg#endif
1047428d7b3dSmrg
1048428d7b3dSmrg	return TRUE;
1049428d7b3dSmrg}
1050428d7b3dSmrg
1051428d7b3dSmrgstatic void sna_dri_init(struct sna *sna, ScreenPtr screen)
1052428d7b3dSmrg{
1053428d7b3dSmrg	char str[128] = "";
1054428d7b3dSmrg
1055428d7b3dSmrg	if (sna->dri2.available)
1056428d7b3dSmrg		sna->dri2.open = sna_dri2_open(sna, screen);
1057428d7b3dSmrg	if (sna->dri2.open)
1058428d7b3dSmrg		strcat(str, "DRI2 ");
1059428d7b3dSmrg
1060428d7b3dSmrg	if (sna->dri3.available)
1061428d7b3dSmrg		sna->dri3.open = sna_dri3_open(sna, screen);
1062428d7b3dSmrg	if (sna->dri3.open)
1063428d7b3dSmrg		strcat(str, "DRI3 ");
1064428d7b3dSmrg
1065428d7b3dSmrg	if (*str)
1066428d7b3dSmrg		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
1067428d7b3dSmrg			   "direct rendering: %senabled\n", str);
1068428d7b3dSmrg}
1069428d7b3dSmrg
1070428d7b3dSmrgstatic Bool
1071428d7b3dSmrgsna_mode_init(struct sna *sna, ScreenPtr screen)
1072428d7b3dSmrg{
1073428d7b3dSmrg	rrScrPrivPtr rp;
1074428d7b3dSmrg
1075428d7b3dSmrg	if (!xf86CrtcScreenInit(screen))
1076428d7b3dSmrg		return FALSE;
1077428d7b3dSmrg
1078428d7b3dSmrg	xf86RandR12SetRotations(screen, RR_Rotate_All | RR_Reflect_All);
1079428d7b3dSmrg	xf86RandR12SetTransformSupport(screen, TRUE);
1080428d7b3dSmrg
1081428d7b3dSmrg	/* Wrap RR queries to catch pending MST topology changes */
1082428d7b3dSmrg	rp = rrGetScrPriv(screen);
1083428d7b3dSmrg	if (rp) {
1084428d7b3dSmrg		sna->mode.rrGetInfo = rp->rrGetInfo;
1085428d7b3dSmrg		rp->rrGetInfo = sna_randr_getinfo;
1086428d7b3dSmrg	}
1087428d7b3dSmrg
1088428d7b3dSmrg	return TRUE;
1089428d7b3dSmrg}
1090428d7b3dSmrg
1091428d7b3dSmrgstatic Bool
1092428d7b3dSmrgsna_screen_init(SCREEN_INIT_ARGS_DECL)
1093428d7b3dSmrg{
1094428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1095428d7b3dSmrg	struct sna *sna = to_sna(scrn);
1096428d7b3dSmrg	VisualPtr visuals;
1097428d7b3dSmrg	DepthPtr depths;
1098428d7b3dSmrg	int nvisuals;
1099428d7b3dSmrg	int ndepths;
1100428d7b3dSmrg	int rootdepth;
1101428d7b3dSmrg	VisualID defaultVisual;
1102428d7b3dSmrg
1103428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
1104428d7b3dSmrg
1105428d7b3dSmrg	assert(sna->scrn == scrn);
1106428d7b3dSmrg	assert(scrn->pScreen == NULL); /* set afterwards */
1107428d7b3dSmrg
1108428d7b3dSmrg	assert(sna->freed_pixmap == NULL);
1109428d7b3dSmrg
1110428d7b3dSmrg	if (!sna_register_all_privates())
1111428d7b3dSmrg		return FALSE;
1112428d7b3dSmrg
1113428d7b3dSmrg	scrn->videoRam = sna->kgem.aperture_mappable * 4; /* Page to KiB */
1114428d7b3dSmrg
1115428d7b3dSmrg	miClearVisualTypes();
1116428d7b3dSmrg	if (!miSetVisualTypes(scrn->depth,
1117428d7b3dSmrg			      miGetDefaultVisualMask(scrn->depth),
1118428d7b3dSmrg			      scrn->rgbBits, scrn->defaultVisual))
1119428d7b3dSmrg		return FALSE;
1120428d7b3dSmrg	if (!miSetPixmapDepths())
1121428d7b3dSmrg		return FALSE;
1122428d7b3dSmrg
1123428d7b3dSmrg	rootdepth = 0;
1124428d7b3dSmrg	if (!miInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &rootdepth,
1125428d7b3dSmrg			   &defaultVisual,
1126428d7b3dSmrg			   ((unsigned long)1 << (scrn->bitsPerPixel - 1)),
1127428d7b3dSmrg			   8, -1))
1128428d7b3dSmrg		return FALSE;
1129428d7b3dSmrg
1130428d7b3dSmrg	if (!miScreenInit(screen, NULL,
1131428d7b3dSmrg			  scrn->virtualX, scrn->virtualY,
1132428d7b3dSmrg			  scrn->xDpi, scrn->yDpi, 0,
1133428d7b3dSmrg			  rootdepth, ndepths, depths,
1134428d7b3dSmrg			  defaultVisual, nvisuals, visuals))
1135428d7b3dSmrg		return FALSE;
1136428d7b3dSmrg
1137428d7b3dSmrg	if (scrn->bitsPerPixel > 8) {
1138428d7b3dSmrg		/* Fixup RGB ordering */
1139428d7b3dSmrg		VisualPtr visual = screen->visuals + screen->numVisuals;
1140428d7b3dSmrg		while (--visual >= screen->visuals) {
1141428d7b3dSmrg			if ((visual->class | DynamicClass) == DirectColor) {
1142428d7b3dSmrg				visual->offsetRed = scrn->offset.red;
1143428d7b3dSmrg				visual->offsetGreen = scrn->offset.green;
1144428d7b3dSmrg				visual->offsetBlue = scrn->offset.blue;
1145428d7b3dSmrg				visual->redMask = scrn->mask.red;
1146428d7b3dSmrg				visual->greenMask = scrn->mask.green;
1147428d7b3dSmrg				visual->blueMask = scrn->mask.blue;
1148428d7b3dSmrg			}
1149428d7b3dSmrg		}
1150428d7b3dSmrg	}
1151428d7b3dSmrg
1152428d7b3dSmrg	assert(screen->CloseScreen == NULL);
1153428d7b3dSmrg	screen->CloseScreen = sna_late_close_screen;
1154428d7b3dSmrg	if (!sna_accel_init(screen, sna)) {
1155428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1156428d7b3dSmrg			   "Hardware acceleration initialization failed\n");
1157428d7b3dSmrg		return FALSE;
1158428d7b3dSmrg	}
1159428d7b3dSmrg
1160428d7b3dSmrg	xf86SetBlackWhitePixels(screen);
1161428d7b3dSmrg
1162428d7b3dSmrg	xf86SetBackingStore(screen);
1163428d7b3dSmrg	xf86SetSilkenMouse(screen);
1164428d7b3dSmrg	if (!miDCInitialize(screen, xf86GetPointerScreenFuncs()))
1165428d7b3dSmrg		return FALSE;
1166428d7b3dSmrg
1167428d7b3dSmrg	if (sna_cursors_init(screen, sna))
1168428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "HW Cursor enabled\n");
1169428d7b3dSmrg
1170428d7b3dSmrg	/* Must force it before EnterVT, so we are in control of VT and
1171428d7b3dSmrg	 * later memory should be bound when allocating, e.g rotate_mem */
1172428d7b3dSmrg	scrn->vtSema = TRUE;
1173428d7b3dSmrg
1174428d7b3dSmrg	sna->BlockHandler = screen->BlockHandler;
1175428d7b3dSmrg	screen->BlockHandler = sna_block_handler;
1176428d7b3dSmrg
1177428d7b3dSmrg	sna->WakeupHandler = screen->WakeupHandler;
1178428d7b3dSmrg	screen->WakeupHandler = sna_wakeup_handler;
1179428d7b3dSmrg
1180428d7b3dSmrg	screen->SaveScreen = sna_save_screen;
1181428d7b3dSmrg	screen->CreateScreenResources = sna_create_screen_resources;
1182428d7b3dSmrg
1183428d7b3dSmrg	sna->CloseScreen = screen->CloseScreen;
1184428d7b3dSmrg	screen->CloseScreen = sna_early_close_screen;
1185428d7b3dSmrg
1186428d7b3dSmrg	if (!sna_mode_init(sna, screen))
1187428d7b3dSmrg		return FALSE;
1188428d7b3dSmrg
1189428d7b3dSmrg	if (!miCreateDefColormap(screen))
1190428d7b3dSmrg		return FALSE;
1191428d7b3dSmrg
1192428d7b3dSmrg	if (sna->mode.num_real_crtc &&
1193428d7b3dSmrg	    !xf86HandleColormaps(screen, 256, 8, sna_load_palette, NULL,
1194428d7b3dSmrg				 CMAP_RELOAD_ON_MODE_SWITCH |
1195428d7b3dSmrg				 CMAP_PALETTED_TRUECOLOR))
1196428d7b3dSmrg		return FALSE;
1197428d7b3dSmrg
1198428d7b3dSmrg	xf86DPMSInit(screen, sna_dpms_set, 0);
1199428d7b3dSmrg
1200428d7b3dSmrg	sna_uevent_init(sna);
1201428d7b3dSmrg	sna_video_init(sna, screen);
1202428d7b3dSmrg	sna_dri_init(sna, screen);
1203428d7b3dSmrg
1204428d7b3dSmrg	if (sna->present.available)
1205428d7b3dSmrg		sna->present.open = sna_present_open(sna, screen);
1206428d7b3dSmrg	if (sna->present.open)
1207428d7b3dSmrg		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
1208428d7b3dSmrg			   "hardware support for Present enabled\n");
1209428d7b3dSmrg
1210428d7b3dSmrg	if (serverGeneration == 1)
1211428d7b3dSmrg		xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
1212428d7b3dSmrg
1213428d7b3dSmrg	sna->suspended = FALSE;
1214428d7b3dSmrg
1215428d7b3dSmrg	return TRUE;
1216428d7b3dSmrg}
1217428d7b3dSmrg
1218428d7b3dSmrgstatic void sna_adjust_frame(ADJUST_FRAME_ARGS_DECL)
1219428d7b3dSmrg{
1220428d7b3dSmrg	SCRN_INFO_PTR(arg);
1221428d7b3dSmrg	DBG(("%s(%d, %d)\n", __FUNCTION__, x, y));
1222428d7b3dSmrg	sna_mode_adjust_frame(to_sna(scrn), x, y);
1223428d7b3dSmrg}
1224428d7b3dSmrg
1225428d7b3dSmrgstatic void sna_free_screen(FREE_SCREEN_ARGS_DECL)
1226428d7b3dSmrg{
1227428d7b3dSmrg	SCRN_INFO_PTR(arg);
1228428d7b3dSmrg	struct sna *sna = to_sna(scrn);
1229428d7b3dSmrg
1230428d7b3dSmrg	DBG(("%s [scrn=%p, sna=%p]\n", __FUNCTION__, scrn, sna));
1231428d7b3dSmrg	if (sna == NULL || (uintptr_t)sna & 3) /* beware thieves */
1232428d7b3dSmrg		return;
1233428d7b3dSmrg
1234428d7b3dSmrg	scrn->driverPrivate = (void *)((uintptr_t)sna->info | (sna->flags & SNA_IS_SLAVED) | 2);
1235428d7b3dSmrg
1236428d7b3dSmrg	sna_mode_fini(sna);
1237428d7b3dSmrg	sna_acpi_fini(sna);
1238428d7b3dSmrg
1239428d7b3dSmrg	intel_put_device(sna->dev);
1240428d7b3dSmrg	free(sna);
1241428d7b3dSmrg}
1242428d7b3dSmrg
1243428d7b3dSmrgstatic Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
1244428d7b3dSmrg{
1245428d7b3dSmrg	SCRN_INFO_PTR(arg);
1246428d7b3dSmrg	struct sna *sna = to_sna(scrn);
1247428d7b3dSmrg
1248428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
1249428d7b3dSmrg	if (intel_get_master(sna->dev))
1250428d7b3dSmrg		return FALSE;
1251428d7b3dSmrg
1252428d7b3dSmrg	if (sna->flags & SNA_REPROBE) {
1253428d7b3dSmrg		DBG(("%s: reporting deferred hotplug event\n",
1254428d7b3dSmrg		     __FUNCTION__));
1255428d7b3dSmrg		sna_mode_discover(sna);
1256428d7b3dSmrg		RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
1257428d7b3dSmrg		sna->flags &= ~SNA_REPROBE;
1258428d7b3dSmrg	}
1259428d7b3dSmrg
1260428d7b3dSmrg	if (!sna_set_desired_mode(sna)) {
1261428d7b3dSmrg		intel_put_master(sna->dev);
1262428d7b3dSmrg		return FALSE;
1263428d7b3dSmrg	}
1264428d7b3dSmrg
1265428d7b3dSmrg	sna_accel_enter(sna);
1266428d7b3dSmrg	return TRUE;
1267428d7b3dSmrg}
1268428d7b3dSmrg
1269428d7b3dSmrgstatic Bool sna_switch_mode(SWITCH_MODE_ARGS_DECL)
1270428d7b3dSmrg{
1271428d7b3dSmrg	SCRN_INFO_PTR(arg);
1272428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
1273428d7b3dSmrg	return xf86SetSingleMode(scrn, mode, RR_Rotate_0);
1274428d7b3dSmrg}
1275428d7b3dSmrg
1276428d7b3dSmrgstatic ModeStatus
1277428d7b3dSmrgsna_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
1278428d7b3dSmrg{
1279428d7b3dSmrg	return MODE_OK;
1280428d7b3dSmrg}
1281428d7b3dSmrg
1282428d7b3dSmrg#ifndef SUSPEND_SLEEP
1283428d7b3dSmrg#define SUSPEND_SLEEP 0
1284428d7b3dSmrg#endif
1285428d7b3dSmrg#ifndef RESUME_SLEEP
1286428d7b3dSmrg#define RESUME_SLEEP 0
1287428d7b3dSmrg#endif
1288428d7b3dSmrg
1289428d7b3dSmrg/*
1290428d7b3dSmrg * This function is only required if we need to do anything differently from
1291428d7b3dSmrg * DoApmEvent() in common/xf86PM.c, including if we want to see events other
1292428d7b3dSmrg * than suspend/resume.
1293428d7b3dSmrg */
1294428d7b3dSmrgstatic Bool sna_pm_event(SCRN_ARG_TYPE arg, pmEvent event, Bool undo)
1295428d7b3dSmrg{
1296428d7b3dSmrg	SCRN_INFO_PTR(arg);
1297428d7b3dSmrg	struct sna *sna = to_sna(scrn);
1298428d7b3dSmrg
1299428d7b3dSmrg	DBG(("%s\n", __FUNCTION__));
1300428d7b3dSmrg
1301428d7b3dSmrg	switch (event) {
1302428d7b3dSmrg	case XF86_APM_SYS_SUSPEND:
1303428d7b3dSmrg	case XF86_APM_CRITICAL_SUSPEND:	/*do we want to delay a critical suspend? */
1304428d7b3dSmrg	case XF86_APM_USER_SUSPEND:
1305428d7b3dSmrg	case XF86_APM_SYS_STANDBY:
1306428d7b3dSmrg	case XF86_APM_USER_STANDBY:
1307428d7b3dSmrg		if (!undo && !sna->suspended) {
1308428d7b3dSmrg			scrn->LeaveVT(VT_FUNC_ARGS(0));
1309428d7b3dSmrg			sna->suspended = TRUE;
1310428d7b3dSmrg			sleep(SUSPEND_SLEEP);
1311428d7b3dSmrg		} else if (undo && sna->suspended) {
1312428d7b3dSmrg			sleep(RESUME_SLEEP);
1313428d7b3dSmrg			scrn->EnterVT(VT_FUNC_ARGS(0));
1314428d7b3dSmrg			sna->suspended = FALSE;
1315428d7b3dSmrg		}
1316428d7b3dSmrg		break;
1317428d7b3dSmrg	case XF86_APM_STANDBY_RESUME:
1318428d7b3dSmrg	case XF86_APM_NORMAL_RESUME:
1319428d7b3dSmrg	case XF86_APM_CRITICAL_RESUME:
1320428d7b3dSmrg		if (sna->suspended) {
1321428d7b3dSmrg			sleep(RESUME_SLEEP);
1322428d7b3dSmrg			scrn->EnterVT(VT_FUNC_ARGS(0));
1323428d7b3dSmrg			sna->suspended = FALSE;
1324428d7b3dSmrg			/*
1325428d7b3dSmrg			 * Turn the screen saver off when resuming.  This seems to be
1326428d7b3dSmrg			 * needed to stop xscreensaver kicking in (when used).
1327428d7b3dSmrg			 *
1328428d7b3dSmrg			 * XXX DoApmEvent() should probably call this just like
1329428d7b3dSmrg			 * xf86VTSwitch() does.  Maybe do it here only in 4.2
1330428d7b3dSmrg			 * compatibility mode.
1331428d7b3dSmrg			 */
1332428d7b3dSmrg			SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
1333428d7b3dSmrg		}
1334428d7b3dSmrg		break;
1335428d7b3dSmrg		/* This is currently used for ACPI */
1336428d7b3dSmrg	case XF86_APM_CAPABILITY_CHANGED:
1337428d7b3dSmrg		SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
1338428d7b3dSmrg		break;
1339428d7b3dSmrg
1340428d7b3dSmrg	default:
1341428d7b3dSmrg		ERR(("sna_pm_event: received APM event %d\n", event));
1342428d7b3dSmrg	}
1343428d7b3dSmrg	return TRUE;
1344428d7b3dSmrg}
1345428d7b3dSmrg
1346428d7b3dSmrgstatic Bool sna_enter_vt__hosted(VT_FUNC_ARGS_DECL)
1347428d7b3dSmrg{
1348428d7b3dSmrg	return TRUE;
1349428d7b3dSmrg}
1350428d7b3dSmrg
1351428d7b3dSmrgstatic void sna_leave_vt__hosted(VT_FUNC_ARGS_DECL)
1352428d7b3dSmrg{
1353428d7b3dSmrg}
1354428d7b3dSmrg
1355428d7b3dSmrgstatic void describe_kms(ScrnInfoPtr scrn)
1356428d7b3dSmrg{
1357428d7b3dSmrg	int fd = __intel_peek_fd(scrn);
1358428d7b3dSmrg	drm_version_t version;
1359428d7b3dSmrg	char name[128] = "";
1360428d7b3dSmrg	char date[128] = "";
1361428d7b3dSmrg
1362428d7b3dSmrg	memset(&version, 0, sizeof(version));
1363428d7b3dSmrg	version.name_len = sizeof(name) - 1;
1364428d7b3dSmrg	version.name = name;
1365428d7b3dSmrg	version.date_len = sizeof(date) - 1;
1366428d7b3dSmrg	version.date = date;
1367428d7b3dSmrg
1368428d7b3dSmrg	if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
1369428d7b3dSmrg		return;
1370428d7b3dSmrg
1371428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1372428d7b3dSmrg		   "Using Kernel Mode Setting driver: %s, version %d.%d.%d %s\n",
1373428d7b3dSmrg		   version.name,
1374428d7b3dSmrg		   version.version_major, version.version_minor, version.version_patchlevel,
1375428d7b3dSmrg		   version.date);
1376428d7b3dSmrg}
1377428d7b3dSmrg
1378428d7b3dSmrgstatic void describe_sna(ScrnInfoPtr scrn)
1379428d7b3dSmrg{
1380428d7b3dSmrg#if defined(USE_GIT_DESCRIBE)
1381428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1382428d7b3dSmrg		   "SNA compiled from %s\n", git_version);
1383428d7b3dSmrg#elif defined(BUILDER_DESCRIPTION)
1384428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1385428d7b3dSmrg		   "SNA compiled: %s\n", BUILDER_DESCRIPTION);
1386428d7b3dSmrg#endif
1387428d7b3dSmrg#if !NDEBUG
1388428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1389428d7b3dSmrg		   "SNA compiled with assertions enabled\n");
1390428d7b3dSmrg#endif
1391428d7b3dSmrg#if DEBUG_SYNC
1392428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1393428d7b3dSmrg		   "SNA compiled with synchronous rendering\n");
1394428d7b3dSmrg#endif
1395428d7b3dSmrg#if DEBUG_MEMORY
1396428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1397428d7b3dSmrg		   "SNA compiled with memory allocation reporting enabled\n");
1398428d7b3dSmrg#endif
1399428d7b3dSmrg#if DEBUG_PIXMAP
1400428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1401428d7b3dSmrg		   "SNA compiled with extra pixmap/damage validation\n");
1402428d7b3dSmrg#endif
1403428d7b3dSmrg#ifdef HAVE_VALGRIND
1404428d7b3dSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1405428d7b3dSmrg		   "SNA compiled for use with valgrind\n");
1406428d7b3dSmrg	VALGRIND_PRINTF("SNA compiled for use with valgrind\n");
1407428d7b3dSmrg#endif
1408428d7b3dSmrg	DBG(("pixman version: %s\n", pixman_version_string()));
1409428d7b3dSmrg}
1410428d7b3dSmrg
1411428d7b3dSmrgBool sna_init_scrn(ScrnInfoPtr scrn, int entity_num)
1412428d7b3dSmrg{
1413428d7b3dSmrg	DBG(("%s: entity_num=%d\n", __FUNCTION__, entity_num));
1414428d7b3dSmrg	describe_kms(scrn);
1415428d7b3dSmrg	describe_sna(scrn);
1416428d7b3dSmrg
1417428d7b3dSmrg	scrn->PreInit = sna_pre_init;
1418428d7b3dSmrg	scrn->ScreenInit = sna_screen_init;
1419428d7b3dSmrg	if (!hosted()) {
1420428d7b3dSmrg		scrn->SwitchMode = sna_switch_mode;
1421428d7b3dSmrg		scrn->AdjustFrame = sna_adjust_frame;
1422428d7b3dSmrg		scrn->EnterVT = sna_enter_vt;
1423428d7b3dSmrg		scrn->LeaveVT = sna_leave_vt;
1424428d7b3dSmrg		scrn->ValidMode = sna_valid_mode;
1425428d7b3dSmrg		scrn->PMEvent = sna_pm_event;
1426428d7b3dSmrg	} else {
1427428d7b3dSmrg		scrn->EnterVT = sna_enter_vt__hosted;
1428428d7b3dSmrg		scrn->LeaveVT = sna_leave_vt__hosted;
1429428d7b3dSmrg	}
1430428d7b3dSmrg	scrn->FreeScreen = sna_free_screen;
1431428d7b3dSmrg
1432428d7b3dSmrg	xf86SetEntitySharable(entity_num);
1433428d7b3dSmrg	xf86SetEntityInstanceForScreen(scrn, entity_num,
1434428d7b3dSmrg				       xf86GetNumEntityInstances(entity_num)-1);
1435428d7b3dSmrg
1436428d7b3dSmrg	sna_threads_init();
1437428d7b3dSmrg
1438428d7b3dSmrg	return TRUE;
1439428d7b3dSmrg}
1440428d7b3dSmrg
1441428d7b3dSmrg#if HAS_DEBUG_FULL
1442428d7b3dSmrg_X_ATTRIBUTE_PRINTF(1, 0) void LogF(const char *f, ...)
1443428d7b3dSmrg{
1444428d7b3dSmrg	va_list ap;
1445428d7b3dSmrg
1446428d7b3dSmrg	/* As we not only may be called from any context, we may also
1447428d7b3dSmrg	 * be called from a thread whilst the main thread is handling
1448428d7b3dSmrg	 * signals, therefore we have to use the signal-safe variants
1449428d7b3dSmrg	 * or else we trip over false positive assertions.
1450428d7b3dSmrg	 */
1451428d7b3dSmrg
1452428d7b3dSmrg	va_start(ap, f);
1453428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
1454428d7b3dSmrg	LogVMessageVerbSigSafe(X_NONE, 1, f, ap);
1455428d7b3dSmrg#else
1456428d7b3dSmrg	LogVMessageVerb(X_NONE, 1, f, ap);
1457428d7b3dSmrg#endif
1458428d7b3dSmrg	va_end(ap);
1459428d7b3dSmrg}
1460428d7b3dSmrg#endif
1461