sna_driver.c revision 13496ba1
103b705cfSriastradh/**************************************************************************
203b705cfSriastradh
303b705cfSriastradhCopyright 2001 VA Linux Systems Inc., Fremont, California.
403b705cfSriastradhCopyright © 2002 by David Dawes
503b705cfSriastradh
603b705cfSriastradhAll Rights Reserved.
703b705cfSriastradh
803b705cfSriastradhPermission is hereby granted, free of charge, to any person obtaining a
903b705cfSriastradhcopy of this software and associated documentation files (the "Software"),
1003b705cfSriastradhto deal in the Software without restriction, including without limitation
1103b705cfSriastradhon the rights to use, copy, modify, merge, publish, distribute, sub
1203b705cfSriastradhlicense, and/or sell copies of the Software, and to permit persons to whom
1303b705cfSriastradhthe Software is furnished to do so, subject to the following conditions:
1403b705cfSriastradh
1503b705cfSriastradhThe above copyright notice and this permission notice (including the next
1603b705cfSriastradhparagraph) shall be included in all copies or substantial portions of the
1703b705cfSriastradhSoftware.
1803b705cfSriastradh
1903b705cfSriastradhTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2003b705cfSriastradhIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2103b705cfSriastradhFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2203b705cfSriastradhTHE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
2303b705cfSriastradhDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2403b705cfSriastradhOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2503b705cfSriastradhUSE OR OTHER DEALINGS IN THE SOFTWARE.
2603b705cfSriastradh
2703b705cfSriastradh**************************************************************************/
2803b705cfSriastradh
2903b705cfSriastradh/*
3003b705cfSriastradh * Authors: Jeff Hartmann <jhartmann@valinux.com>
3103b705cfSriastradh *          Abraham van der Merwe <abraham@2d3d.co.za>
3203b705cfSriastradh *          David Dawes <dawes@xfree86.org>
3303b705cfSriastradh *          Alan Hourihane <alanh@tungstengraphics.com>
3403b705cfSriastradh */
3503b705cfSriastradh
3603b705cfSriastradh#ifdef HAVE_CONFIG_H
3703b705cfSriastradh#include "config.h"
3803b705cfSriastradh#endif
3903b705cfSriastradh
4003b705cfSriastradh#include <string.h>
4103b705cfSriastradh#include <stdio.h>
4203b705cfSriastradh#include <unistd.h>
4303b705cfSriastradh#include <stdlib.h>
4403b705cfSriastradh#include <stdio.h>
4503b705cfSriastradh#include <errno.h>
4603b705cfSriastradh
4703b705cfSriastradh#include "sna.h"
4803b705cfSriastradh#include "sna_module.h"
4903b705cfSriastradh#include "sna_video.h"
5003b705cfSriastradh
5103b705cfSriastradh#include "intel_driver.h"
5203b705cfSriastradh#include "intel_options.h"
5303b705cfSriastradh
5442542f5fSchristos#include <xf86cmap.h>
5542542f5fSchristos#include <xf86drm.h>
5642542f5fSchristos#include <xf86RandR12.h>
5742542f5fSchristos#include <mi.h>
5842542f5fSchristos#include <micmap.h>
5942542f5fSchristos
6003b705cfSriastradh#include <sys/ioctl.h>
6103b705cfSriastradh#include <sys/fcntl.h>
6213496ba1Ssnj#include <sys/poll.h>
6303b705cfSriastradh#include "i915_drm.h"
6403b705cfSriastradh
6503b705cfSriastradh#ifdef HAVE_VALGRIND
6603b705cfSriastradh#include <valgrind.h>
6703b705cfSriastradh#include <memcheck.h>
6803b705cfSriastradh#endif
6903b705cfSriastradh
7003b705cfSriastradh#if HAVE_DOT_GIT
7103b705cfSriastradh#include "git_version.h"
7203b705cfSriastradh#endif
7303b705cfSriastradh
7442542f5fSchristos#ifdef TEARFREE
7542542f5fSchristos#define ENABLE_TEAR_FREE TRUE
7642542f5fSchristos#else
7742542f5fSchristos#define ENABLE_TEAR_FREE FALSE
7842542f5fSchristos#endif
7942542f5fSchristos
8003b705cfSriastradhDevPrivateKeyRec sna_pixmap_key;
8103b705cfSriastradhDevPrivateKeyRec sna_gc_key;
8203b705cfSriastradhDevPrivateKeyRec sna_window_key;
8303b705cfSriastradhDevPrivateKeyRec sna_glyph_key;
8403b705cfSriastradhDevPrivateKeyRec sna_client_key;
8503b705cfSriastradh
8603b705cfSriastradhstatic void
8703b705cfSriastradhsna_load_palette(ScrnInfoPtr scrn, int numColors, int *indices,
8803b705cfSriastradh		 LOCO * colors, VisualPtr pVisual)
8903b705cfSriastradh{
9003b705cfSriastradh	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
9142542f5fSchristos	int p, n, i, j;
9203b705cfSriastradh	uint16_t lut_r[256], lut_g[256], lut_b[256];
9303b705cfSriastradh
9403b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
9503b705cfSriastradh
9603b705cfSriastradh	for (p = 0; p < xf86_config->num_crtc; p++) {
9703b705cfSriastradh		xf86CrtcPtr crtc = xf86_config->crtc[p];
9803b705cfSriastradh
9942542f5fSchristos#define C(I,RGB) (colors[I].RGB << 8 | colors[I].RGB)
10003b705cfSriastradh		switch (scrn->depth) {
10103b705cfSriastradh		case 15:
10242542f5fSchristos			for (n = 0; n < numColors; n++) {
10342542f5fSchristos				i = indices[n];
10403b705cfSriastradh				for (j = 0; j < 8; j++) {
10542542f5fSchristos					lut_r[8*i + j] = C(i, red);
10642542f5fSchristos					lut_g[8*i + j] = C(i, green);
10742542f5fSchristos					lut_b[8*i + j] = C(i, blue);
10803b705cfSriastradh				}
10903b705cfSriastradh			}
11003b705cfSriastradh			break;
11103b705cfSriastradh		case 16:
11242542f5fSchristos			for (n = 0; n < numColors; n++) {
11342542f5fSchristos				i = indices[n];
11403b705cfSriastradh
11542542f5fSchristos				if (i <= 31) {
11603b705cfSriastradh					for (j = 0; j < 8; j++) {
11742542f5fSchristos						lut_r[8*i + j] = C(i, red);
11842542f5fSchristos						lut_b[8*i + j] = C(i, blue);
11903b705cfSriastradh					}
12003b705cfSriastradh				}
12103b705cfSriastradh
12242542f5fSchristos				for (j = 0; j < 4; j++)
12342542f5fSchristos					lut_g[4*i + j] = C(i, green);
12403b705cfSriastradh			}
12503b705cfSriastradh			break;
12603b705cfSriastradh		default:
12742542f5fSchristos			for (n = 0; n < numColors; n++) {
12842542f5fSchristos				i = indices[n];
12942542f5fSchristos				lut_r[i] = C(i, red);
13042542f5fSchristos				lut_g[i] = C(i, green);
13142542f5fSchristos				lut_b[i] = C(i, blue);
13203b705cfSriastradh			}
13303b705cfSriastradh			break;
13403b705cfSriastradh		}
13542542f5fSchristos#undef C
13603b705cfSriastradh
13703b705cfSriastradh		/* Make the change through RandR */
13803b705cfSriastradh#ifdef RANDR_12_INTERFACE
13903b705cfSriastradh		RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
14003b705cfSriastradh#else
14103b705cfSriastradh		crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
14203b705cfSriastradh#endif
14303b705cfSriastradh	}
14403b705cfSriastradh}
14503b705cfSriastradh
14603b705cfSriastradhstatic void
14703b705cfSriastradhsna_set_fallback_mode(ScrnInfoPtr scrn)
14803b705cfSriastradh{
14903b705cfSriastradh	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
15003b705cfSriastradh	xf86OutputPtr output = NULL;
15103b705cfSriastradh	xf86CrtcPtr crtc = NULL;
15203b705cfSriastradh	int n;
15303b705cfSriastradh
15403b705cfSriastradh	if ((unsigned)config->compat_output < config->num_output) {
15503b705cfSriastradh		output = config->output[config->compat_output];
15603b705cfSriastradh		crtc = output->crtc;
15703b705cfSriastradh	}
15803b705cfSriastradh
15903b705cfSriastradh	for (n = 0; n < config->num_output; n++)
16003b705cfSriastradh		config->output[n]->crtc = NULL;
16103b705cfSriastradh	for (n = 0; n < config->num_crtc; n++)
16203b705cfSriastradh		config->crtc[n]->enabled = FALSE;
16303b705cfSriastradh
16403b705cfSriastradh	if (output && crtc) {
16503b705cfSriastradh		DisplayModePtr mode;
16603b705cfSriastradh
16703b705cfSriastradh		output->crtc = crtc;
16803b705cfSriastradh
16903b705cfSriastradh		mode = xf86OutputFindClosestMode(output, scrn->currentMode);
17003b705cfSriastradh		if (mode &&
17103b705cfSriastradh		    xf86CrtcSetModeTransform(crtc, mode, RR_Rotate_0, NULL, 0, 0)) {
17203b705cfSriastradh			crtc->desiredMode = *mode;
17303b705cfSriastradh			crtc->desiredMode.prev = crtc->desiredMode.next = NULL;
17403b705cfSriastradh			crtc->desiredMode.name = NULL;
17503b705cfSriastradh			crtc->desiredMode.PrivSize = 0;
17603b705cfSriastradh			crtc->desiredMode.PrivFlags = 0;
17703b705cfSriastradh			crtc->desiredMode.Private = NULL;
17803b705cfSriastradh			crtc->desiredRotation = RR_Rotate_0;
17903b705cfSriastradh			crtc->desiredTransformPresent = FALSE;
18003b705cfSriastradh			crtc->desiredX = 0;
18103b705cfSriastradh			crtc->desiredY = 0;
18203b705cfSriastradh			crtc->enabled = TRUE;
18303b705cfSriastradh		}
18403b705cfSriastradh	}
18503b705cfSriastradh
18603b705cfSriastradh	xf86DisableUnusedFunctions(scrn);
18703b705cfSriastradh#ifdef RANDR_12_INTERFACE
18803b705cfSriastradh	if (get_root_window(scrn->pScreen))
18903b705cfSriastradh		xf86RandR12TellChanged(scrn->pScreen);
19003b705cfSriastradh#endif
19103b705cfSriastradh}
19203b705cfSriastradh
19342542f5fSchristosstatic Bool sna_set_desired_mode(struct sna *sna)
19403b705cfSriastradh{
19503b705cfSriastradh	ScrnInfoPtr scrn = sna->scrn;
19603b705cfSriastradh
19703b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
19803b705cfSriastradh
19903b705cfSriastradh	if (!xf86SetDesiredModes(scrn)) {
20003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
20103b705cfSriastradh			   "failed to restore desired modes on VT switch\n");
20203b705cfSriastradh		sna_set_fallback_mode(scrn);
20303b705cfSriastradh	}
20403b705cfSriastradh
20542542f5fSchristos	sna_mode_check(sna);
20603b705cfSriastradh	return TRUE;
20703b705cfSriastradh}
20803b705cfSriastradh
20903b705cfSriastradh/**
21003b705cfSriastradh * Adjust the screen pixmap for the current location of the front buffer.
21103b705cfSriastradh * This is done at EnterVT when buffers are bound as long as the resources
21203b705cfSriastradh * have already been created, but the first EnterVT happens before
21303b705cfSriastradh * CreateScreenResources.
21403b705cfSriastradh */
21503b705cfSriastradhstatic Bool sna_create_screen_resources(ScreenPtr screen)
21603b705cfSriastradh{
21703b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
21842542f5fSchristos	PixmapPtr new_front;
21942542f5fSchristos	unsigned hint;
22003b705cfSriastradh
22103b705cfSriastradh	DBG(("%s(%dx%d@%d)\n", __FUNCTION__,
22203b705cfSriastradh	     screen->width, screen->height, screen->rootDepth));
22303b705cfSriastradh
22403b705cfSriastradh	assert(sna->scrn == xf86ScreenToScrn(screen));
22503b705cfSriastradh	assert(sna->scrn->pScreen == screen);
22603b705cfSriastradh
22742542f5fSchristos	/* free the data used during miInitScreen */
22803b705cfSriastradh	free(screen->devPrivate);
22903b705cfSriastradh	screen->devPrivate = NULL;
23003b705cfSriastradh
23103b705cfSriastradh	sna_accel_create(sna);
23203b705cfSriastradh
23342542f5fSchristos	hint = SNA_CREATE_FB;
23442542f5fSchristos	if (sna->flags & SNA_IS_HOSTED)
23542542f5fSchristos		hint = 0;
23642542f5fSchristos
23742542f5fSchristos	new_front = screen->CreatePixmap(screen,
23842542f5fSchristos					 screen->width,
23942542f5fSchristos					 screen->height,
24042542f5fSchristos					 screen->rootDepth,
24142542f5fSchristos					 hint);
24242542f5fSchristos	if (!new_front) {
24303b705cfSriastradh		xf86DrvMsg(screen->myNum, X_ERROR,
24403b705cfSriastradh			   "[intel] Unable to create front buffer %dx%d at depth %d\n",
24503b705cfSriastradh			   screen->width,
24603b705cfSriastradh			   screen->height,
24703b705cfSriastradh			   screen->rootDepth);
24803b705cfSriastradh
24903b705cfSriastradh		return FALSE;
25003b705cfSriastradh	}
25103b705cfSriastradh
25213496ba1Ssnj	/* Prefer to use the GPU for rendering into the eventual scanout
25313496ba1Ssnj	 * bo so that we do not unduly stall when it is time to attach
25413496ba1Ssnj	 * it to the CRTCs.
25513496ba1Ssnj	 */
25613496ba1Ssnj	(void)sna_pixmap_force_to_gpu(new_front, MOVE_READ | __MOVE_SCANOUT);
25703b705cfSriastradh
25842542f5fSchristos	screen->SetScreenPixmap(new_front);
25942542f5fSchristos	assert(screen->GetScreenPixmap(screen) == new_front);
26042542f5fSchristos	assert(sna->front == new_front);
26142542f5fSchristos	screen->DestroyPixmap(new_front); /* transfer ownership to screen */
26242542f5fSchristos
26342542f5fSchristos	sna_mode_set_primary(sna);
26403b705cfSriastradh
26513496ba1Ssnj	/* Try to become master and copy the current fbcon before the
26613496ba1Ssnj	 * actual VT switch. If we fail here, we will try to reset the
26713496ba1Ssnj	 * mode in the eventual VT switch. This can fail if systemd has
26813496ba1Ssnj	 * already revoked our KMS privileges, so just carry on regardless,
26913496ba1Ssnj	 * and hope that everything is sorted after the VT switch.
27013496ba1Ssnj	 */
27113496ba1Ssnj	if (intel_get_master(sna->dev) == 0) {
27213496ba1Ssnj		/* Only preserve the fbcon, not any subsequent server regens */
27313496ba1Ssnj		if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
27413496ba1Ssnj			sna_copy_fbcon(sna);
27503b705cfSriastradh
27613496ba1Ssnj		(void)sna_set_desired_mode(sna);
27703b705cfSriastradh	}
27803b705cfSriastradh
27903b705cfSriastradh	return TRUE;
28003b705cfSriastradh}
28103b705cfSriastradh
28242542f5fSchristosstatic Bool sna_save_screen(ScreenPtr screen, int mode)
28303b705cfSriastradh{
28442542f5fSchristos	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
28542542f5fSchristos
28642542f5fSchristos	DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
28742542f5fSchristos	if (!scrn->vtSema)
28842542f5fSchristos		return FALSE;
28942542f5fSchristos
29042542f5fSchristos	xf86SaveScreen(screen, mode);
29142542f5fSchristos	sna_crtc_config_notify(screen);
29242542f5fSchristos	return TRUE;
29303b705cfSriastradh}
29403b705cfSriastradh
29542542f5fSchristosstatic void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
29603b705cfSriastradh{
29742542f5fSchristos	DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
29842542f5fSchristos	if (!scrn->vtSema)
29942542f5fSchristos		return;
30003b705cfSriastradh
30142542f5fSchristos	xf86DPMSSet(scrn, mode, flags);
30242542f5fSchristos	sna_crtc_config_notify(xf86ScrnToScreen(scrn));
30342542f5fSchristos}
30403b705cfSriastradh
30542542f5fSchristosstatic void sna_selftest(void)
30642542f5fSchristos{
30742542f5fSchristos	sna_damage_selftest();
30842542f5fSchristos}
30903b705cfSriastradh
31042542f5fSchristosstatic bool has_vsync(struct sna *sna)
31142542f5fSchristos{
31242542f5fSchristos	if (sna->flags & SNA_IS_HOSTED)
31303b705cfSriastradh		return false;
31403b705cfSriastradh
31542542f5fSchristos	return true;
31603b705cfSriastradh}
31703b705cfSriastradh
31803b705cfSriastradhstatic void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
31903b705cfSriastradh{
32003b705cfSriastradh#if HAS_PIXMAP_SHARING && defined(DRM_CAP_PRIME)
32103b705cfSriastradh	uint64_t value;
32203b705cfSriastradh
32303b705cfSriastradh	scrn->capabilities = 0;
32403b705cfSriastradh	if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0) {
32503b705cfSriastradh		if (value & DRM_PRIME_CAP_EXPORT)
32603b705cfSriastradh			scrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SinkOffload;
32703b705cfSriastradh		if (value & DRM_PRIME_CAP_IMPORT)
32803b705cfSriastradh			scrn->capabilities |= RR_Capability_SinkOutput;
32903b705cfSriastradh	}
33003b705cfSriastradh#endif
33103b705cfSriastradh}
33203b705cfSriastradh
33342542f5fSchristosstatic int
33442542f5fSchristosnamecmp(const char *s1, const char *s2)
33542542f5fSchristos{
33642542f5fSchristos	char c1, c2;
33742542f5fSchristos
33842542f5fSchristos	if (!s1 || *s1 == 0) {
33942542f5fSchristos		if (!s2 || *s2 == 0)
34042542f5fSchristos			return 0;
34142542f5fSchristos		else
34242542f5fSchristos			return 1;
34342542f5fSchristos	}
34442542f5fSchristos
34542542f5fSchristos	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
34642542f5fSchristos		s1++;
34742542f5fSchristos
34842542f5fSchristos	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
34942542f5fSchristos		s2++;
35042542f5fSchristos
35142542f5fSchristos	c1 = isupper(*s1) ? tolower(*s1) : *s1;
35242542f5fSchristos	c2 = isupper(*s2) ? tolower(*s2) : *s2;
35342542f5fSchristos	while (c1 == c2) {
35442542f5fSchristos		if (c1 == '\0')
35542542f5fSchristos			return 0;
35642542f5fSchristos
35742542f5fSchristos		s1++;
35842542f5fSchristos		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
35942542f5fSchristos			s1++;
36042542f5fSchristos
36142542f5fSchristos		s2++;
36242542f5fSchristos		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
36342542f5fSchristos			s2++;
36442542f5fSchristos
36542542f5fSchristos		c1 = isupper(*s1) ? tolower(*s1) : *s1;
36642542f5fSchristos		c2 = isupper(*s2) ? tolower(*s2) : *s2;
36742542f5fSchristos	}
36842542f5fSchristos
36942542f5fSchristos	return c1 - c2;
37042542f5fSchristos}
37142542f5fSchristos
37203b705cfSriastradhstatic Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
37303b705cfSriastradh{
37442542f5fSchristos	const char *str = xf86GetOptValString(sna->Options, id);
37542542f5fSchristos
37642542f5fSchristos	if (str == NULL)
37742542f5fSchristos		return val;
37842542f5fSchristos
37942542f5fSchristos	if (*str == '\0')
38042542f5fSchristos		return TRUE;
38142542f5fSchristos
38242542f5fSchristos	if (namecmp(str, "1") == 0)
38342542f5fSchristos		return TRUE;
38442542f5fSchristos	if (namecmp(str, "on") == 0)
38542542f5fSchristos		return TRUE;
38642542f5fSchristos	if (namecmp(str, "true") == 0)
38742542f5fSchristos		return TRUE;
38842542f5fSchristos	if (namecmp(str, "yes") == 0)
38942542f5fSchristos		return TRUE;
39042542f5fSchristos
39142542f5fSchristos	if (namecmp(str, "0") == 0)
39242542f5fSchristos		return FALSE;
39342542f5fSchristos	if (namecmp(str, "off") == 0)
39442542f5fSchristos		return FALSE;
39542542f5fSchristos	if (namecmp(str, "false") == 0)
39642542f5fSchristos		return FALSE;
39742542f5fSchristos	if (namecmp(str, "no") == 0)
39842542f5fSchristos		return FALSE;
39942542f5fSchristos
40042542f5fSchristos	return val;
40142542f5fSchristos}
40242542f5fSchristos
40342542f5fSchristosstatic unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val)
40442542f5fSchristos{
40542542f5fSchristos	const char *str = xf86GetOptValString(sna->Options, id);
40642542f5fSchristos	unsigned v;
40742542f5fSchristos
40842542f5fSchristos	if (str == NULL || *str == '\0')
40942542f5fSchristos		return val;
41042542f5fSchristos
41142542f5fSchristos	if (namecmp(str, "on") == 0)
41242542f5fSchristos		return val;
41342542f5fSchristos	if (namecmp(str, "true") == 0)
41442542f5fSchristos		return val;
41542542f5fSchristos	if (namecmp(str, "yes") == 0)
41642542f5fSchristos		return val;
41742542f5fSchristos
41842542f5fSchristos	if (namecmp(str, "0") == 0)
41942542f5fSchristos		return 0;
42042542f5fSchristos	if (namecmp(str, "off") == 0)
42142542f5fSchristos		return 0;
42242542f5fSchristos	if (namecmp(str, "false") == 0)
42342542f5fSchristos		return 0;
42442542f5fSchristos	if (namecmp(str, "no") == 0)
42542542f5fSchristos		return 0;
42642542f5fSchristos
42742542f5fSchristos	v = atoi(str);
42842542f5fSchristos	if (v)
42942542f5fSchristos		return v;
43042542f5fSchristos
43103b705cfSriastradh	return val;
43203b705cfSriastradh}
43303b705cfSriastradh
43403b705cfSriastradhstatic Bool fb_supports_depth(int fd, int depth)
43503b705cfSriastradh{
43603b705cfSriastradh	struct drm_i915_gem_create create;
43703b705cfSriastradh	struct drm_mode_fb_cmd fb;
43842542f5fSchristos	struct drm_mode_card_res res;
43903b705cfSriastradh	Bool ret;
44003b705cfSriastradh
44142542f5fSchristos	memset(&res, 0, sizeof(res));
44242542f5fSchristos	(void)drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
44342542f5fSchristos	if (res.count_crtcs == 0)
44442542f5fSchristos		return TRUE;
44542542f5fSchristos
44603b705cfSriastradh	VG_CLEAR(create);
44703b705cfSriastradh	create.handle = 0;
44803b705cfSriastradh	create.size = 4096;
44903b705cfSriastradh	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create))
45003b705cfSriastradh		return FALSE;
45103b705cfSriastradh
45203b705cfSriastradh	VG_CLEAR(fb);
45303b705cfSriastradh	fb.width = 64;
45403b705cfSriastradh	fb.height = 16;
45503b705cfSriastradh	fb.pitch = 256;
45603b705cfSriastradh	fb.bpp = depth <= 8 ? 8 : depth <= 16 ? 16 : 32;
45703b705cfSriastradh	fb.depth = depth;
45803b705cfSriastradh	fb.handle = create.handle;
45903b705cfSriastradh
46003b705cfSriastradh	ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB, &fb) == 0;
46103b705cfSriastradh	drmModeRmFB(fd, fb.fb_id);
46203b705cfSriastradh
46342542f5fSchristos	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
46403b705cfSriastradh
46503b705cfSriastradh	return ret;
46603b705cfSriastradh}
46703b705cfSriastradh
46842542f5fSchristosstatic void setup_dri(struct sna *sna)
46942542f5fSchristos{
47042542f5fSchristos	unsigned level;
47142542f5fSchristos
47242542f5fSchristos	sna->dri2.available = false;
47342542f5fSchristos	sna->dri3.available = false;
47442542f5fSchristos
47542542f5fSchristos	level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0);
47642542f5fSchristos#if HAVE_DRI3
47742542f5fSchristos	if (level >= 3)
47842542f5fSchristos		sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
47942542f5fSchristos#endif
48042542f5fSchristos#if HAVE_DRI2
48142542f5fSchristos	if (level >= 2)
48242542f5fSchristos		sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
48342542f5fSchristos#endif
48442542f5fSchristos}
48542542f5fSchristos
48642542f5fSchristosstatic bool enable_tear_free(struct sna *sna)
48742542f5fSchristos{
48842542f5fSchristos	if (sna->flags & SNA_LINEAR_FB)
48942542f5fSchristos		return false;
49042542f5fSchristos
49142542f5fSchristos	/* Under certain conditions, we should enable TearFree by default,
49242542f5fSchristos	 * for example when the hardware requires pageflipping to run within
49342542f5fSchristos	 * its power/performance budget.
49442542f5fSchristos	 */
49542542f5fSchristos	if (sna_mode_wants_tear_free(sna))
49642542f5fSchristos		return true;
49742542f5fSchristos
49842542f5fSchristos	return ENABLE_TEAR_FREE;
49942542f5fSchristos}
50042542f5fSchristos
50142542f5fSchristosstatic void setup_tear_free(struct sna *sna)
50242542f5fSchristos{
50342542f5fSchristos	MessageType from;
50442542f5fSchristos	Bool enable;
50542542f5fSchristos
50642542f5fSchristos	if (sna->flags & SNA_LINEAR_FB)
50742542f5fSchristos		return;
50842542f5fSchristos
50942542f5fSchristos	if ((sna->flags & SNA_HAS_FLIP) == 0) {
51042542f5fSchristos		from = X_PROBED;
51142542f5fSchristos		goto done;
51242542f5fSchristos	}
51342542f5fSchristos
51442542f5fSchristos	if (!xf86GetOptValBool(sna->Options, OPTION_TEAR_FREE, &enable)) {
51542542f5fSchristos		enable = enable_tear_free(sna);
51642542f5fSchristos		from = X_DEFAULT;
51742542f5fSchristos	} else
51842542f5fSchristos		from = X_CONFIG;
51942542f5fSchristos
52042542f5fSchristos	if (enable)
52142542f5fSchristos		sna->flags |= SNA_TEAR_FREE;
52242542f5fSchristos
52342542f5fSchristosdone:
52442542f5fSchristos	xf86DrvMsg(sna->scrn->scrnIndex, from, "TearFree %sabled\n",
52542542f5fSchristos		   sna->flags & SNA_TEAR_FREE ? "en" : "dis");
52642542f5fSchristos}
52742542f5fSchristos
52803b705cfSriastradh/**
52903b705cfSriastradh * This is called before ScreenInit to do any require probing of screen
53003b705cfSriastradh * configuration.
53103b705cfSriastradh *
53203b705cfSriastradh * This code generally covers probing, module loading, option handling
53303b705cfSriastradh * card mapping, and RandR setup.
53403b705cfSriastradh *
53503b705cfSriastradh * Since xf86InitialConfiguration ends up requiring that we set video modes
53603b705cfSriastradh * in order to detect configuration, we end up having to do a lot of driver
53703b705cfSriastradh * setup (talking to the DRM, mapping the device, etc.) in this function.
53803b705cfSriastradh * As a result, we want to set up that server initialization once rather
53903b705cfSriastradh * that doing it per generation.
54003b705cfSriastradh */
54142542f5fSchristosstatic Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
54203b705cfSriastradh{
54303b705cfSriastradh	struct sna *sna;
54403b705cfSriastradh	char buf[1024];
54503b705cfSriastradh	rgb defaultWeight = { 0, 0, 0 };
54603b705cfSriastradh	EntityInfoPtr pEnt;
54703b705cfSriastradh	Gamma zeros = { 0.0, 0.0, 0.0 };
54803b705cfSriastradh	int fd;
54903b705cfSriastradh
55003b705cfSriastradh	DBG(("%s flags=%x, numEntities=%d\n",
55142542f5fSchristos	     __FUNCTION__, probe, scrn->numEntities));
55203b705cfSriastradh
55303b705cfSriastradh	if (scrn->numEntities != 1)
55403b705cfSriastradh		return FALSE;
55503b705cfSriastradh
55603b705cfSriastradh	pEnt = xf86GetEntityInfo(scrn->entityList[0]);
55742542f5fSchristos	if (pEnt == NULL) {
55842542f5fSchristos		ERR(("%s: no EntityInfo found for scrn\n", __FUNCTION__));
55903b705cfSriastradh		return FALSE;
56042542f5fSchristos	}
56103b705cfSriastradh
56203b705cfSriastradh	if (pEnt->location.type != BUS_PCI
56303b705cfSriastradh#ifdef XSERVER_PLATFORM_BUS
56403b705cfSriastradh	    && pEnt->location.type != BUS_PLATFORM
56503b705cfSriastradh#endif
56642542f5fSchristos		) {
56742542f5fSchristos		ERR(("%s: invalid EntityInfo found for scrn, location=%d\n", __FUNCTION__, pEnt->location.type));
56803b705cfSriastradh		return FALSE;
56942542f5fSchristos	}
57003b705cfSriastradh
57142542f5fSchristos	if (probe & PROBE_DETECT)
57203b705cfSriastradh		return TRUE;
57303b705cfSriastradh
57403b705cfSriastradh	sna_selftest();
57503b705cfSriastradh
57642542f5fSchristos	probe = 0;
57742542f5fSchristos	if (((uintptr_t)scrn->driverPrivate) & 3) {
57803b705cfSriastradh		if (posix_memalign((void **)&sna, 4096, sizeof(*sna)))
57903b705cfSriastradh			return FALSE;
58003b705cfSriastradh
58103b705cfSriastradh		memset(sna, 0, sizeof(*sna)); /* should be unnecessary */
58242542f5fSchristos		probe = (uintptr_t)scrn->driverPrivate & 1;
58342542f5fSchristos		sna->info = (void *)((uintptr_t)scrn->driverPrivate & ~3);
58403b705cfSriastradh		scrn->driverPrivate = sna;
58503b705cfSriastradh
58603b705cfSriastradh		sna->cpu_features = sna_cpu_detect();
58742542f5fSchristos		sna->acpi.fd = sna_acpi_open();
58803b705cfSriastradh	}
58903b705cfSriastradh	sna = to_sna(scrn);
59003b705cfSriastradh	sna->scrn = scrn;
59103b705cfSriastradh	sna->pEnt = pEnt;
59242542f5fSchristos	sna->flags = probe;
59303b705cfSriastradh
59403b705cfSriastradh	scrn->displayWidth = 640;	/* default it */
59503b705cfSriastradh
59603b705cfSriastradh	scrn->monitor = scrn->confScreen->monitor;
59703b705cfSriastradh	scrn->progClock = TRUE;
59803b705cfSriastradh	scrn->rgbBits = 8;
59903b705cfSriastradh
60013496ba1Ssnj	sna->dev = intel_get_device(scrn, &fd);
60113496ba1Ssnj	if (sna->dev == NULL) {
60203b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
60303b705cfSriastradh			   "Failed to claim DRM device.\n");
60403b705cfSriastradh		goto cleanup;
60503b705cfSriastradh	}
60603b705cfSriastradh
60703b705cfSriastradh	/* Sanity check */
60803b705cfSriastradh	if (hosted() && (sna->flags & SNA_IS_HOSTED) == 0) {
60903b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
61003b705cfSriastradh			   "Failed to setup hosted device.\n");
61103b705cfSriastradh		goto cleanup;
61203b705cfSriastradh	}
61303b705cfSriastradh
61413496ba1Ssnj	intel_detect_chipset(scrn, sna->dev);
61542542f5fSchristos	xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
61642542f5fSchristos		   sna_cpu_features_to_string(sna->cpu_features, buf));
61703b705cfSriastradh
61842542f5fSchristos	if (!xf86SetDepthBpp(scrn, 24, 0, 0,
61903b705cfSriastradh			     Support32bppFb |
62003b705cfSriastradh			     SupportConvert24to32 | PreferConvert24to32))
62103b705cfSriastradh		goto cleanup;
62203b705cfSriastradh
62303b705cfSriastradh	switch (scrn->depth) {
62403b705cfSriastradh	case 8:
62503b705cfSriastradh	case 15:
62603b705cfSriastradh	case 16:
62703b705cfSriastradh	case 24:
62803b705cfSriastradh	case 30:
62942542f5fSchristos		if ((sna->flags & SNA_IS_HOSTED) ||
63042542f5fSchristos		    fb_supports_depth(fd, scrn->depth))
63103b705cfSriastradh			break;
63203b705cfSriastradh	default:
63303b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
63403b705cfSriastradh			   "Given depth (%d) is not supported by the Intel driver and this chipset.\n",
63503b705cfSriastradh			   scrn->depth);
63603b705cfSriastradh		goto cleanup;
63703b705cfSriastradh	}
63803b705cfSriastradh	xf86PrintDepthBpp(scrn);
63903b705cfSriastradh
64003b705cfSriastradh	if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
64103b705cfSriastradh		goto cleanup;
64203b705cfSriastradh	if (!xf86SetDefaultVisual(scrn, -1))
64303b705cfSriastradh		goto cleanup;
64403b705cfSriastradh
64503b705cfSriastradh	sna->Options = intel_options_get(scrn);
64603b705cfSriastradh	if (sna->Options == NULL)
64703b705cfSriastradh		goto cleanup;
64803b705cfSriastradh
64903b705cfSriastradh	sna_setup_capabilities(scrn, fd);
65003b705cfSriastradh
65142542f5fSchristos	kgem_init(&sna->kgem, fd,
65242542f5fSchristos		  xf86GetPciInfoForEntity(pEnt->index),
65342542f5fSchristos		  sna->info->gen);
65403b705cfSriastradh	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
65503b705cfSriastradh	    !sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
65603b705cfSriastradh		xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
65703b705cfSriastradh			   "Disabling hardware acceleration.\n");
65803b705cfSriastradh		sna->kgem.wedged = true;
65903b705cfSriastradh	}
66003b705cfSriastradh
66103b705cfSriastradh	if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
66242542f5fSchristos		sna->flags |= SNA_LINEAR_FB;
66342542f5fSchristos
66442542f5fSchristos	if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE))
66542542f5fSchristos		sna->flags |= SNA_REMOVE_OUTPUTS;
66603b705cfSriastradh
66703b705cfSriastradh	if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
66803b705cfSriastradh		sna->flags |= SNA_NO_WAIT;
66942542f5fSchristos	DBG(("%s: swapbuffer wait? %s\n", __FUNCTION__, sna->flags & SNA_NO_WAIT ? "disabled" : "enabled"));
67042542f5fSchristos
67142542f5fSchristos	if (!has_vsync(sna) ||
67242542f5fSchristos	    !xf86ReturnOptValBool(sna->Options, OPTION_VSYNC, TRUE))
67342542f5fSchristos		sna->flags |= SNA_NO_VSYNC;
67442542f5fSchristos	DBG(("%s: vsync? %s\n", __FUNCTION__, sna->flags & SNA_NO_VSYNC ? "disabled" : "enabled"));
67542542f5fSchristos
67642542f5fSchristos	if (sna->flags & SNA_IS_HOSTED ||
67742542f5fSchristos	    !xf86ReturnOptValBool(sna->Options, OPTION_PAGEFLIP, TRUE))
67803b705cfSriastradh		sna->flags |= SNA_NO_FLIP;
67942542f5fSchristos	DBG(("%s: page flips? %s\n", __FUNCTION__, sna->flags & SNA_NO_FLIP ? "disabled" : "enabled"));
68003b705cfSriastradh
68142542f5fSchristos	if ((sna->flags & (SNA_NO_VSYNC | SNA_NO_FLIP | SNA_NO_WAIT)) == 0 &&
68242542f5fSchristos	    xf86ReturnOptValBool(sna->Options, OPTION_TRIPLE_BUFFER, TRUE))
68342542f5fSchristos		sna->flags |= SNA_TRIPLE_BUFFER;
68442542f5fSchristos	DBG(("%s: triple buffer? %s\n", __FUNCTION__, sna->flags & SNA_TRIPLE_BUFFER ? "enabled" : "disabled"));
68503b705cfSriastradh
68642542f5fSchristos	if (xf86ReturnOptValBool(sna->Options, OPTION_CRTC_PIXMAPS, FALSE)) {
68742542f5fSchristos		xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Forcing per-crtc-pixmaps.\n");
68842542f5fSchristos		sna->flags |= SNA_FORCE_SHADOW;
68942542f5fSchristos	}
69003b705cfSriastradh
69103b705cfSriastradh	if (!sna_mode_pre_init(scrn, sna)) {
69203b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
69303b705cfSriastradh			   "No outputs and no modes.\n");
69403b705cfSriastradh		goto cleanup;
69503b705cfSriastradh	}
69603b705cfSriastradh	scrn->currentMode = scrn->modes;
69703b705cfSriastradh
69842542f5fSchristos	setup_tear_free(sna);
69942542f5fSchristos
70003b705cfSriastradh	xf86SetGamma(scrn, zeros);
70103b705cfSriastradh	xf86SetDpi(scrn, 0, 0);
70203b705cfSriastradh
70342542f5fSchristos	setup_dri(sna);
70442542f5fSchristos
70542542f5fSchristos	sna->present.available = false;
70642542f5fSchristos	if (xf86ReturnOptValBool(sna->Options, OPTION_PRESENT, TRUE)) {
70742542f5fSchristos#if HAVE_PRESENT
70842542f5fSchristos		sna->present.available = !!xf86LoadSubModule(scrn, "present");
70942542f5fSchristos#endif
71042542f5fSchristos	}
71142542f5fSchristos
71242542f5fSchristos	sna_acpi_init(sna);
71303b705cfSriastradh
71403b705cfSriastradh	return TRUE;
71503b705cfSriastradh
71603b705cfSriastradhcleanup:
71742542f5fSchristos	scrn->driverPrivate = (void *)((uintptr_t)sna->info | (sna->flags & SNA_IS_SLAVED) | 2);
71813496ba1Ssnj	if (sna->dev)
71913496ba1Ssnj		intel_put_device(sna->dev);
72003b705cfSriastradh	free(sna);
72103b705cfSriastradh	return FALSE;
72203b705cfSriastradh}
72303b705cfSriastradh
72442542f5fSchristosstatic bool has_shadow(struct sna *sna)
72542542f5fSchristos{
72642542f5fSchristos	if (!sna->mode.shadow_damage)
72742542f5fSchristos		return false;
72842542f5fSchristos
72942542f5fSchristos	if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
73042542f5fSchristos		return false;
73142542f5fSchristos
73242542f5fSchristos	return sna->mode.flip_active == 0;
73342542f5fSchristos}
73442542f5fSchristos
73503b705cfSriastradhstatic void
73603b705cfSriastradhsna_block_handler(BLOCKHANDLER_ARGS_DECL)
73703b705cfSriastradh{
73803b705cfSriastradh#ifndef XF86_SCRN_INTERFACE
73903b705cfSriastradh	struct sna *sna = to_sna(xf86Screens[arg]);
74003b705cfSriastradh#else
74103b705cfSriastradh	struct sna *sna = to_sna_from_screen(arg);
74203b705cfSriastradh#endif
74303b705cfSriastradh	struct timeval **tv = timeout;
74403b705cfSriastradh
74503b705cfSriastradh	DBG(("%s (tv=%ld.%06ld)\n", __FUNCTION__,
74603b705cfSriastradh	     *tv ? (*tv)->tv_sec : -1, *tv ? (*tv)->tv_usec : 0));
74703b705cfSriastradh
74803b705cfSriastradh	sna->BlockHandler(BLOCKHANDLER_ARGS);
74903b705cfSriastradh
75042542f5fSchristos	if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec) || has_shadow(sna))
75103b705cfSriastradh		sna_accel_block_handler(sna, tv);
75203b705cfSriastradh}
75303b705cfSriastradh
75403b705cfSriastradhstatic void
75503b705cfSriastradhsna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
75603b705cfSriastradh{
75703b705cfSriastradh#ifndef XF86_SCRN_INTERFACE
75803b705cfSriastradh	struct sna *sna = to_sna(xf86Screens[arg]);
75903b705cfSriastradh#else
76003b705cfSriastradh	struct sna *sna = to_sna_from_screen(arg);
76103b705cfSriastradh#endif
76203b705cfSriastradh
76303b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
76403b705cfSriastradh
76503b705cfSriastradh	/* despite all appearances, result is just a signed int */
76603b705cfSriastradh	if ((int)result < 0)
76703b705cfSriastradh		return;
76803b705cfSriastradh
76942542f5fSchristos	sna_acpi_wakeup(sna, read_mask);
77042542f5fSchristos
77103b705cfSriastradh	sna->WakeupHandler(WAKEUPHANDLER_ARGS);
77203b705cfSriastradh
77303b705cfSriastradh	sna_accel_wakeup_handler(sna);
77403b705cfSriastradh
77513496ba1Ssnj	if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask)) {
77603b705cfSriastradh		sna_mode_wakeup(sna);
77713496ba1Ssnj		/* Clear the flag so that subsequent ZaphodHeads don't block  */
77813496ba1Ssnj		FD_CLR(sna->kgem.fd, (fd_set*)read_mask);
77913496ba1Ssnj	}
78003b705cfSriastradh}
78103b705cfSriastradh
78203b705cfSriastradh#if HAVE_UDEV
78303b705cfSriastradhstatic void
78403b705cfSriastradhsna_handle_uevents(int fd, void *closure)
78503b705cfSriastradh{
78642542f5fSchristos	struct sna *sna = closure;
78703b705cfSriastradh	struct udev_device *dev;
78842542f5fSchristos	const char *str;
78903b705cfSriastradh	struct stat s;
79003b705cfSriastradh	dev_t udev_devnum;
79103b705cfSriastradh
79203b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
79303b705cfSriastradh
79403b705cfSriastradh	dev = udev_monitor_receive_device(sna->uevent_monitor);
79503b705cfSriastradh	if (!dev)
79603b705cfSriastradh		return;
79703b705cfSriastradh
79803b705cfSriastradh	udev_devnum = udev_device_get_devnum(dev);
79942542f5fSchristos	if (fstat(sna->kgem.fd, &s) || memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))) {
80003b705cfSriastradh		udev_device_unref(dev);
80103b705cfSriastradh		return;
80203b705cfSriastradh	}
80303b705cfSriastradh
80442542f5fSchristos	str = udev_device_get_property_value(dev, "HOTPLUG");
80542542f5fSchristos	if (str && atoi(str) == 1) {
80642542f5fSchristos		ScrnInfoPtr scrn = sna->scrn;
80703b705cfSriastradh
80842542f5fSchristos		DBG(("%s: hotplug event (vtSema?=%d)\n", __FUNCTION__, scrn->vtSema));
80903b705cfSriastradh
81042542f5fSchristos		if (scrn->vtSema) {
81142542f5fSchristos			sna_mode_discover(sna);
81242542f5fSchristos			sna_mode_check(sna);
81303b705cfSriastradh			RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
81403b705cfSriastradh		} else
81503b705cfSriastradh			sna->flags |= SNA_REPROBE;
81603b705cfSriastradh	}
81703b705cfSriastradh
81803b705cfSriastradh	udev_device_unref(dev);
81903b705cfSriastradh}
82003b705cfSriastradh
82103b705cfSriastradhstatic void
82242542f5fSchristossna_uevent_init(struct sna *sna)
82303b705cfSriastradh{
82403b705cfSriastradh	struct udev *u;
82503b705cfSriastradh	struct udev_monitor *mon;
82603b705cfSriastradh	MessageType from = X_CONFIG;
82703b705cfSriastradh
82803b705cfSriastradh	if (sna->flags & SNA_IS_HOSTED)
82903b705cfSriastradh		return;
83003b705cfSriastradh
83103b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
83203b705cfSriastradh
83303b705cfSriastradh	/* RandR will be disabled if Xinerama is active, and so generating
83403b705cfSriastradh	 * RR hotplug events is then verboten.
83503b705cfSriastradh	 */
83603b705cfSriastradh	if (!dixPrivateKeyRegistered(rrPrivKey))
83742542f5fSchristos		goto out;
83803b705cfSriastradh
83942542f5fSchristos	u = NULL;
84042542f5fSchristos	if (xf86ReturnOptValBool(sna->Options, OPTION_HOTPLUG, TRUE))
84142542f5fSchristos		u = udev_new();
84203b705cfSriastradh	if (!u)
84342542f5fSchristos		goto out;
84442542f5fSchristos
84542542f5fSchristos	from = X_DEFAULT;
84603b705cfSriastradh
84703b705cfSriastradh	mon = udev_monitor_new_from_netlink(u, "udev");
84842542f5fSchristos	if (!mon)
84942542f5fSchristos		goto err_dev;
85003b705cfSriastradh
85142542f5fSchristos	if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0)
85242542f5fSchristos		goto err_monitor;
85303b705cfSriastradh
85442542f5fSchristos	if (udev_monitor_enable_receiving(mon) < 0)
85542542f5fSchristos		goto err_monitor;
85603b705cfSriastradh
85742542f5fSchristos	sna->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
85842542f5fSchristos						    sna_handle_uevents, sna);
85942542f5fSchristos	if (!sna->uevent_handler)
86042542f5fSchristos		goto err_monitor;
86103b705cfSriastradh
86242542f5fSchristos	sna->uevent_monitor = mon;
86342542f5fSchristosout:
86442542f5fSchristos	xf86DrvMsg(sna->scrn->scrnIndex, from, "display hotplug detection %s\n",
86542542f5fSchristos		   sna->uevent_monitor ? "enabled" : "disabled");
86642542f5fSchristos	return;
86742542f5fSchristos
86842542f5fSchristoserr_monitor:
86942542f5fSchristos	udev_monitor_unref(mon);
87042542f5fSchristoserr_dev:
87142542f5fSchristos	udev_unref(u);
87242542f5fSchristos	goto out;
87303b705cfSriastradh}
87403b705cfSriastradh
87513496ba1Ssnjstatic bool sna_uevent_poll(struct sna *sna)
87613496ba1Ssnj{
87713496ba1Ssnj	struct pollfd pfd;
87813496ba1Ssnj
87913496ba1Ssnj	if (sna->uevent_monitor == NULL)
88013496ba1Ssnj		return false;
88113496ba1Ssnj
88213496ba1Ssnj	pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
88313496ba1Ssnj	pfd.events = POLLIN;
88413496ba1Ssnj
88513496ba1Ssnj	while (poll(&pfd, 1, 0) > 0)
88613496ba1Ssnj		sna_handle_uevents(pfd.fd, sna);
88713496ba1Ssnj
88813496ba1Ssnj	return true;
88913496ba1Ssnj}
89013496ba1Ssnj
89103b705cfSriastradhstatic void
89242542f5fSchristossna_uevent_fini(struct sna *sna)
89303b705cfSriastradh{
89403b705cfSriastradh	struct udev *u;
89503b705cfSriastradh
89603b705cfSriastradh	if (sna->uevent_handler == NULL)
89703b705cfSriastradh		return;
89803b705cfSriastradh
89903b705cfSriastradh	xf86RemoveGeneralHandler(sna->uevent_handler);
90003b705cfSriastradh
90103b705cfSriastradh	u = udev_monitor_get_udev(sna->uevent_monitor);
90203b705cfSriastradh	udev_monitor_unref(sna->uevent_monitor);
90303b705cfSriastradh	udev_unref(u);
90403b705cfSriastradh
90503b705cfSriastradh	sna->uevent_handler = NULL;
90603b705cfSriastradh	sna->uevent_monitor = NULL;
90703b705cfSriastradh
90803b705cfSriastradh	DBG(("%s: removed uvent handler\n", __FUNCTION__));
90903b705cfSriastradh}
91003b705cfSriastradh#else
91142542f5fSchristosstatic void sna_uevent_init(struct sna *sna) { }
91213496ba1Ssnjstatic bool sna_uevent_poll(struct sna *sna) { return false; }
91342542f5fSchristosstatic void sna_uevent_fini(struct sna *sna) { }
91403b705cfSriastradh#endif /* HAVE_UDEV */
91503b705cfSriastradh
91613496ba1Ssnjstatic Bool
91713496ba1Ssnjsna_randr_getinfo(ScreenPtr screen, Rotation *rotations)
91813496ba1Ssnj{
91913496ba1Ssnj	struct sna *sna = to_sna_from_screen(screen);
92013496ba1Ssnj
92113496ba1Ssnj	if (!sna_uevent_poll(sna))
92213496ba1Ssnj		sna_mode_discover(sna);
92313496ba1Ssnj
92413496ba1Ssnj	return sna->mode.rrGetInfo(screen, rotations);
92513496ba1Ssnj}
92613496ba1Ssnj
92703b705cfSriastradhstatic void sna_leave_vt(VT_FUNC_ARGS_DECL)
92803b705cfSriastradh{
92903b705cfSriastradh	SCRN_INFO_PTR(arg);
93042542f5fSchristos	struct sna *sna = to_sna(scrn);
93103b705cfSriastradh
93203b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
93303b705cfSriastradh
93442542f5fSchristos	sna_accel_leave(sna);
93542542f5fSchristos	sna_mode_reset(sna);
93603b705cfSriastradh
93713496ba1Ssnj	if (intel_put_master(sna->dev))
93803b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
93903b705cfSriastradh			   "drmDropMaster failed: %s\n", strerror(errno));
94003b705cfSriastradh}
94103b705cfSriastradh
94203b705cfSriastradhstatic Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
94303b705cfSriastradh{
94403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
94503b705cfSriastradh	struct sna *sna = to_sna(scrn);
94603b705cfSriastradh
94703b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
94803b705cfSriastradh
94903b705cfSriastradh	/* XXX Note that we will leak kernel resources if !vtSema */
95003b705cfSriastradh
95142542f5fSchristos	sna_uevent_fini(sna);
95203b705cfSriastradh	sna_mode_close(sna);
95303b705cfSriastradh
95442542f5fSchristos	if (sna->present.open) {
95542542f5fSchristos		sna_present_close(sna, screen);
95642542f5fSchristos		sna->present.open = false;
95742542f5fSchristos	}
95842542f5fSchristos
95942542f5fSchristos	if (sna->dri3.open) {
96042542f5fSchristos		sna_dri3_close(sna, screen);
96142542f5fSchristos		sna->dri3.open = false;
96242542f5fSchristos	}
96342542f5fSchristos
96442542f5fSchristos	if (sna->dri2.open) {
96542542f5fSchristos		sna_dri2_close(sna, screen);
96642542f5fSchristos		sna->dri2.open = false;
96703b705cfSriastradh	}
96803b705cfSriastradh
96903b705cfSriastradh	if (sna->front) {
97003b705cfSriastradh		screen->DestroyPixmap(sna->front);
97103b705cfSriastradh		sna->front = NULL;
97203b705cfSriastradh	}
97303b705cfSriastradh
97403b705cfSriastradh	if (scrn->vtSema) {
97513496ba1Ssnj		intel_put_master(sna->dev);
97603b705cfSriastradh		scrn->vtSema = FALSE;
97703b705cfSriastradh	}
97803b705cfSriastradh
97903b705cfSriastradh	return sna->CloseScreen(CLOSE_SCREEN_ARGS);
98003b705cfSriastradh}
98103b705cfSriastradh
98203b705cfSriastradhstatic Bool sna_late_close_screen(CLOSE_SCREEN_ARGS_DECL)
98303b705cfSriastradh{
98403b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
98503b705cfSriastradh	DepthPtr depths;
98603b705cfSriastradh	int d;
98703b705cfSriastradh
98803b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
98903b705cfSriastradh
99003b705cfSriastradh	sna_accel_close(sna);
99142542f5fSchristos	sna_video_close(sna);
99203b705cfSriastradh
99303b705cfSriastradh	depths = screen->allowedDepths;
99403b705cfSriastradh	for (d = 0; d < screen->numDepths; d++)
99503b705cfSriastradh		free(depths[d].vids);
99603b705cfSriastradh	free(depths);
99703b705cfSriastradh
99803b705cfSriastradh	free(screen->visuals);
99903b705cfSriastradh
100003b705cfSriastradh	return TRUE;
100103b705cfSriastradh}
100203b705cfSriastradh
100303b705cfSriastradhstatic Bool
100403b705cfSriastradhsna_register_all_privates(void)
100503b705cfSriastradh{
100603b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
100703b705cfSriastradh	if (!dixRegisterPrivateKey(&sna_pixmap_key, PRIVATE_PIXMAP,
100803b705cfSriastradh				   3*sizeof(void *)))
100903b705cfSriastradh		return FALSE;
101003b705cfSriastradh
101103b705cfSriastradh	if (!dixRegisterPrivateKey(&sna_gc_key, PRIVATE_GC,
101203b705cfSriastradh				   sizeof(FbGCPrivate)))
101303b705cfSriastradh		return FALSE;
101403b705cfSriastradh
101503b705cfSriastradh	if (!dixRegisterPrivateKey(&sna_glyph_key, PRIVATE_GLYPH,
101603b705cfSriastradh				   sizeof(struct sna_glyph)))
101703b705cfSriastradh		return FALSE;
101803b705cfSriastradh
101903b705cfSriastradh	if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
102003b705cfSriastradh				   3*sizeof(void *)))
102103b705cfSriastradh		return FALSE;
102203b705cfSriastradh
102303b705cfSriastradh	if (!dixRegisterPrivateKey(&sna_client_key, PRIVATE_CLIENT,
102403b705cfSriastradh				   sizeof(struct sna_client)))
102503b705cfSriastradh		return FALSE;
102603b705cfSriastradh#else
102703b705cfSriastradh	if (!dixRequestPrivate(&sna_pixmap_key, 3*sizeof(void *)))
102803b705cfSriastradh		return FALSE;
102903b705cfSriastradh
103003b705cfSriastradh	if (!dixRequestPrivate(&sna_gc_key, sizeof(FbGCPrivate)))
103103b705cfSriastradh		return FALSE;
103203b705cfSriastradh
103303b705cfSriastradh	if (!dixRequestPrivate(&sna_glyph_key, sizeof(struct sna_glyph)))
103403b705cfSriastradh		return FALSE;
103503b705cfSriastradh
103603b705cfSriastradh	if (!dixRequestPrivate(&sna_window_key, 3*sizeof(void *)))
103703b705cfSriastradh		return FALSE;
103803b705cfSriastradh
103903b705cfSriastradh	if (!dixRequestPrivate(&sna_client_key, sizeof(struct sna_client)))
104003b705cfSriastradh		return FALSE;
104103b705cfSriastradh#endif
104203b705cfSriastradh
104303b705cfSriastradh	return TRUE;
104403b705cfSriastradh}
104503b705cfSriastradh
104642542f5fSchristosstatic void sna_dri_init(struct sna *sna, ScreenPtr screen)
104742542f5fSchristos{
104842542f5fSchristos	char str[128] = "";
104942542f5fSchristos
105042542f5fSchristos	if (sna->dri2.available)
105142542f5fSchristos		sna->dri2.open = sna_dri2_open(sna, screen);
105242542f5fSchristos	if (sna->dri2.open)
105342542f5fSchristos		strcat(str, "DRI2 ");
105442542f5fSchristos
105542542f5fSchristos	if (sna->dri3.available)
105642542f5fSchristos		sna->dri3.open = sna_dri3_open(sna, screen);
105742542f5fSchristos	if (sna->dri3.open)
105842542f5fSchristos		strcat(str, "DRI3 ");
105942542f5fSchristos
106042542f5fSchristos	if (*str)
106142542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
106242542f5fSchristos			   "direct rendering: %senabled\n", str);
106342542f5fSchristos}
106442542f5fSchristos
106513496ba1Ssnjstatic Bool
106613496ba1Ssnjsna_mode_init(struct sna *sna, ScreenPtr screen)
106703b705cfSriastradh{
106813496ba1Ssnj	rrScrPrivPtr rp;
106913496ba1Ssnj
107013496ba1Ssnj	if (!xf86CrtcScreenInit(screen))
107113496ba1Ssnj		return FALSE;
107213496ba1Ssnj
107313496ba1Ssnj	xf86RandR12SetRotations(screen, RR_Rotate_All | RR_Reflect_All);
107413496ba1Ssnj	xf86RandR12SetTransformSupport(screen, TRUE);
107513496ba1Ssnj
107613496ba1Ssnj	/* Wrap RR queries to catch pending MST topology changes */
107713496ba1Ssnj	rp = rrGetScrPriv(screen);
107813496ba1Ssnj	if (rp) {
107913496ba1Ssnj		sna->mode.rrGetInfo = rp->rrGetInfo;
108013496ba1Ssnj		rp->rrGetInfo = sna_randr_getinfo;
108113496ba1Ssnj	}
108213496ba1Ssnj
108313496ba1Ssnj	return TRUE;
108403b705cfSriastradh}
108503b705cfSriastradh
108603b705cfSriastradhstatic Bool
108703b705cfSriastradhsna_screen_init(SCREEN_INIT_ARGS_DECL)
108803b705cfSriastradh{
108903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
109003b705cfSriastradh	struct sna *sna = to_sna(scrn);
109103b705cfSriastradh	VisualPtr visuals;
109203b705cfSriastradh	DepthPtr depths;
109303b705cfSriastradh	int nvisuals;
109403b705cfSriastradh	int ndepths;
109503b705cfSriastradh	int rootdepth;
109603b705cfSriastradh	VisualID defaultVisual;
109703b705cfSriastradh
109803b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
109903b705cfSriastradh
110003b705cfSriastradh	assert(sna->scrn == scrn);
110103b705cfSriastradh	assert(scrn->pScreen == NULL); /* set afterwards */
110203b705cfSriastradh
110303b705cfSriastradh	assert(sna->freed_pixmap == NULL);
110403b705cfSriastradh
110503b705cfSriastradh	if (!sna_register_all_privates())
110603b705cfSriastradh		return FALSE;
110703b705cfSriastradh
110813496ba1Ssnj	scrn->videoRam = sna->kgem.aperture_mappable * 4; /* Page to KiB */
110903b705cfSriastradh
111003b705cfSriastradh	miClearVisualTypes();
111103b705cfSriastradh	if (!miSetVisualTypes(scrn->depth,
111203b705cfSriastradh			      miGetDefaultVisualMask(scrn->depth),
111303b705cfSriastradh			      scrn->rgbBits, scrn->defaultVisual))
111403b705cfSriastradh		return FALSE;
111503b705cfSriastradh	if (!miSetPixmapDepths())
111603b705cfSriastradh		return FALSE;
111703b705cfSriastradh
111803b705cfSriastradh	rootdepth = 0;
111903b705cfSriastradh	if (!miInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &rootdepth,
112003b705cfSriastradh			   &defaultVisual,
112103b705cfSriastradh			   ((unsigned long)1 << (scrn->bitsPerPixel - 1)),
112203b705cfSriastradh			   8, -1))
112303b705cfSriastradh		return FALSE;
112403b705cfSriastradh
112503b705cfSriastradh	if (!miScreenInit(screen, NULL,
112603b705cfSriastradh			  scrn->virtualX, scrn->virtualY,
112703b705cfSriastradh			  scrn->xDpi, scrn->yDpi, 0,
112803b705cfSriastradh			  rootdepth, ndepths, depths,
112903b705cfSriastradh			  defaultVisual, nvisuals, visuals))
113003b705cfSriastradh		return FALSE;
113103b705cfSriastradh
113203b705cfSriastradh	if (scrn->bitsPerPixel > 8) {
113303b705cfSriastradh		/* Fixup RGB ordering */
113403b705cfSriastradh		VisualPtr visual = screen->visuals + screen->numVisuals;
113503b705cfSriastradh		while (--visual >= screen->visuals) {
113603b705cfSriastradh			if ((visual->class | DynamicClass) == DirectColor) {
113703b705cfSriastradh				visual->offsetRed = scrn->offset.red;
113803b705cfSriastradh				visual->offsetGreen = scrn->offset.green;
113903b705cfSriastradh				visual->offsetBlue = scrn->offset.blue;
114003b705cfSriastradh				visual->redMask = scrn->mask.red;
114103b705cfSriastradh				visual->greenMask = scrn->mask.green;
114203b705cfSriastradh				visual->blueMask = scrn->mask.blue;
114303b705cfSriastradh			}
114403b705cfSriastradh		}
114503b705cfSriastradh	}
114603b705cfSriastradh
114703b705cfSriastradh	assert(screen->CloseScreen == NULL);
114803b705cfSriastradh	screen->CloseScreen = sna_late_close_screen;
114903b705cfSriastradh	if (!sna_accel_init(screen, sna)) {
115003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
115103b705cfSriastradh			   "Hardware acceleration initialization failed\n");
115203b705cfSriastradh		return FALSE;
115303b705cfSriastradh	}
115403b705cfSriastradh
115503b705cfSriastradh	xf86SetBlackWhitePixels(screen);
115603b705cfSriastradh
115703b705cfSriastradh	xf86SetBackingStore(screen);
115803b705cfSriastradh	xf86SetSilkenMouse(screen);
115903b705cfSriastradh	if (!miDCInitialize(screen, xf86GetPointerScreenFuncs()))
116003b705cfSriastradh		return FALSE;
116103b705cfSriastradh
116242542f5fSchristos	if (sna_cursors_init(screen, sna))
116303b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_INFO, "HW Cursor enabled\n");
116403b705cfSriastradh
116503b705cfSriastradh	/* Must force it before EnterVT, so we are in control of VT and
116603b705cfSriastradh	 * later memory should be bound when allocating, e.g rotate_mem */
116703b705cfSriastradh	scrn->vtSema = TRUE;
116803b705cfSriastradh
116903b705cfSriastradh	sna->BlockHandler = screen->BlockHandler;
117003b705cfSriastradh	screen->BlockHandler = sna_block_handler;
117103b705cfSriastradh
117203b705cfSriastradh	sna->WakeupHandler = screen->WakeupHandler;
117303b705cfSriastradh	screen->WakeupHandler = sna_wakeup_handler;
117403b705cfSriastradh
117542542f5fSchristos	screen->SaveScreen = sna_save_screen;
117603b705cfSriastradh	screen->CreateScreenResources = sna_create_screen_resources;
117703b705cfSriastradh
117803b705cfSriastradh	sna->CloseScreen = screen->CloseScreen;
117903b705cfSriastradh	screen->CloseScreen = sna_early_close_screen;
118003b705cfSriastradh
118113496ba1Ssnj	if (!sna_mode_init(sna, screen))
118203b705cfSriastradh		return FALSE;
118303b705cfSriastradh
118403b705cfSriastradh	if (!miCreateDefColormap(screen))
118503b705cfSriastradh		return FALSE;
118603b705cfSriastradh
118742542f5fSchristos	if (sna->mode.num_real_crtc &&
118842542f5fSchristos	    !xf86HandleColormaps(screen, 256, 8, sna_load_palette, NULL,
118903b705cfSriastradh				 CMAP_RELOAD_ON_MODE_SWITCH |
119042542f5fSchristos				 CMAP_PALETTED_TRUECOLOR))
119103b705cfSriastradh		return FALSE;
119203b705cfSriastradh
119342542f5fSchristos	xf86DPMSInit(screen, sna_dpms_set, 0);
119403b705cfSriastradh
119513496ba1Ssnj	sna_uevent_init(sna);
119603b705cfSriastradh	sna_video_init(sna, screen);
119742542f5fSchristos	sna_dri_init(sna, screen);
119842542f5fSchristos
119942542f5fSchristos	if (sna->present.available)
120042542f5fSchristos		sna->present.open = sna_present_open(sna, screen);
120142542f5fSchristos	if (sna->present.open)
120242542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
120342542f5fSchristos			   "hardware support for Present enabled\n");
120403b705cfSriastradh
120503b705cfSriastradh	if (serverGeneration == 1)
120603b705cfSriastradh		xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
120703b705cfSriastradh
120803b705cfSriastradh	sna->suspended = FALSE;
120903b705cfSriastradh
121003b705cfSriastradh	return TRUE;
121103b705cfSriastradh}
121203b705cfSriastradh
121303b705cfSriastradhstatic void sna_adjust_frame(ADJUST_FRAME_ARGS_DECL)
121403b705cfSriastradh{
121503b705cfSriastradh	SCRN_INFO_PTR(arg);
121603b705cfSriastradh	DBG(("%s(%d, %d)\n", __FUNCTION__, x, y));
121703b705cfSriastradh	sna_mode_adjust_frame(to_sna(scrn), x, y);
121803b705cfSriastradh}
121903b705cfSriastradh
122003b705cfSriastradhstatic void sna_free_screen(FREE_SCREEN_ARGS_DECL)
122103b705cfSriastradh{
122203b705cfSriastradh	SCRN_INFO_PTR(arg);
122303b705cfSriastradh	struct sna *sna = to_sna(scrn);
122403b705cfSriastradh
122542542f5fSchristos	DBG(("%s [scrn=%p, sna=%p]\n", __FUNCTION__, scrn, sna));
122642542f5fSchristos	if (sna == NULL || (uintptr_t)sna & 3) /* beware thieves */
122703b705cfSriastradh		return;
122803b705cfSriastradh
122942542f5fSchristos	scrn->driverPrivate = (void *)((uintptr_t)sna->info | (sna->flags & SNA_IS_SLAVED) | 2);
123003b705cfSriastradh
123103b705cfSriastradh	sna_mode_fini(sna);
123242542f5fSchristos	sna_acpi_fini(sna);
123303b705cfSriastradh
123413496ba1Ssnj	intel_put_device(sna->dev);
123513496ba1Ssnj	free(sna);
123603b705cfSriastradh}
123703b705cfSriastradh
123803b705cfSriastradhstatic Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
123903b705cfSriastradh{
124003b705cfSriastradh	SCRN_INFO_PTR(arg);
124103b705cfSriastradh	struct sna *sna = to_sna(scrn);
124203b705cfSriastradh
124303b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
124413496ba1Ssnj	if (intel_get_master(sna->dev))
124503b705cfSriastradh		return FALSE;
124603b705cfSriastradh
124703b705cfSriastradh	if (sna->flags & SNA_REPROBE) {
124842542f5fSchristos		DBG(("%s: reporting deferred hotplug event\n",
124942542f5fSchristos		     __FUNCTION__));
125042542f5fSchristos		sna_mode_discover(sna);
125103b705cfSriastradh		RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
125203b705cfSriastradh		sna->flags &= ~SNA_REPROBE;
125303b705cfSriastradh	}
125403b705cfSriastradh
125542542f5fSchristos	if (!sna_set_desired_mode(sna)) {
125613496ba1Ssnj		intel_put_master(sna->dev);
125742542f5fSchristos		return FALSE;
125842542f5fSchristos	}
125942542f5fSchristos
126042542f5fSchristos	sna_accel_enter(sna);
126103b705cfSriastradh	return TRUE;
126203b705cfSriastradh}
126303b705cfSriastradh
126403b705cfSriastradhstatic Bool sna_switch_mode(SWITCH_MODE_ARGS_DECL)
126503b705cfSriastradh{
126603b705cfSriastradh	SCRN_INFO_PTR(arg);
126703b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
126803b705cfSriastradh	return xf86SetSingleMode(scrn, mode, RR_Rotate_0);
126903b705cfSriastradh}
127003b705cfSriastradh
127103b705cfSriastradhstatic ModeStatus
127203b705cfSriastradhsna_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
127303b705cfSriastradh{
127403b705cfSriastradh	return MODE_OK;
127503b705cfSriastradh}
127603b705cfSriastradh
127703b705cfSriastradh#ifndef SUSPEND_SLEEP
127803b705cfSriastradh#define SUSPEND_SLEEP 0
127903b705cfSriastradh#endif
128003b705cfSriastradh#ifndef RESUME_SLEEP
128103b705cfSriastradh#define RESUME_SLEEP 0
128203b705cfSriastradh#endif
128303b705cfSriastradh
128403b705cfSriastradh/*
128503b705cfSriastradh * This function is only required if we need to do anything differently from
128603b705cfSriastradh * DoApmEvent() in common/xf86PM.c, including if we want to see events other
128703b705cfSriastradh * than suspend/resume.
128803b705cfSriastradh */
128903b705cfSriastradhstatic Bool sna_pm_event(SCRN_ARG_TYPE arg, pmEvent event, Bool undo)
129003b705cfSriastradh{
129103b705cfSriastradh	SCRN_INFO_PTR(arg);
129203b705cfSriastradh	struct sna *sna = to_sna(scrn);
129303b705cfSriastradh
129403b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
129503b705cfSriastradh
129603b705cfSriastradh	switch (event) {
129703b705cfSriastradh	case XF86_APM_SYS_SUSPEND:
129803b705cfSriastradh	case XF86_APM_CRITICAL_SUSPEND:	/*do we want to delay a critical suspend? */
129903b705cfSriastradh	case XF86_APM_USER_SUSPEND:
130003b705cfSriastradh	case XF86_APM_SYS_STANDBY:
130103b705cfSriastradh	case XF86_APM_USER_STANDBY:
130203b705cfSriastradh		if (!undo && !sna->suspended) {
130303b705cfSriastradh			scrn->LeaveVT(VT_FUNC_ARGS(0));
130403b705cfSriastradh			sna->suspended = TRUE;
130503b705cfSriastradh			sleep(SUSPEND_SLEEP);
130603b705cfSriastradh		} else if (undo && sna->suspended) {
130703b705cfSriastradh			sleep(RESUME_SLEEP);
130803b705cfSriastradh			scrn->EnterVT(VT_FUNC_ARGS(0));
130903b705cfSriastradh			sna->suspended = FALSE;
131003b705cfSriastradh		}
131103b705cfSriastradh		break;
131203b705cfSriastradh	case XF86_APM_STANDBY_RESUME:
131303b705cfSriastradh	case XF86_APM_NORMAL_RESUME:
131403b705cfSriastradh	case XF86_APM_CRITICAL_RESUME:
131503b705cfSriastradh		if (sna->suspended) {
131603b705cfSriastradh			sleep(RESUME_SLEEP);
131703b705cfSriastradh			scrn->EnterVT(VT_FUNC_ARGS(0));
131803b705cfSriastradh			sna->suspended = FALSE;
131903b705cfSriastradh			/*
132003b705cfSriastradh			 * Turn the screen saver off when resuming.  This seems to be
132103b705cfSriastradh			 * needed to stop xscreensaver kicking in (when used).
132203b705cfSriastradh			 *
132303b705cfSriastradh			 * XXX DoApmEvent() should probably call this just like
132403b705cfSriastradh			 * xf86VTSwitch() does.  Maybe do it here only in 4.2
132503b705cfSriastradh			 * compatibility mode.
132603b705cfSriastradh			 */
132703b705cfSriastradh			SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
132803b705cfSriastradh		}
132903b705cfSriastradh		break;
133003b705cfSriastradh		/* This is currently used for ACPI */
133103b705cfSriastradh	case XF86_APM_CAPABILITY_CHANGED:
133203b705cfSriastradh		SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
133303b705cfSriastradh		break;
133403b705cfSriastradh
133503b705cfSriastradh	default:
133642542f5fSchristos		ERR(("sna_pm_event: received APM event %d\n", event));
133703b705cfSriastradh	}
133803b705cfSriastradh	return TRUE;
133903b705cfSriastradh}
134003b705cfSriastradh
134103b705cfSriastradhstatic Bool sna_enter_vt__hosted(VT_FUNC_ARGS_DECL)
134203b705cfSriastradh{
134303b705cfSriastradh	return TRUE;
134403b705cfSriastradh}
134503b705cfSriastradh
134603b705cfSriastradhstatic void sna_leave_vt__hosted(VT_FUNC_ARGS_DECL)
134703b705cfSriastradh{
134803b705cfSriastradh}
134903b705cfSriastradh
135042542f5fSchristosstatic void describe_kms(ScrnInfoPtr scrn)
135142542f5fSchristos{
135242542f5fSchristos	int fd = __intel_peek_fd(scrn);
135342542f5fSchristos	drm_version_t version;
135442542f5fSchristos	char name[128] = "";
135542542f5fSchristos	char date[128] = "";
135642542f5fSchristos
135742542f5fSchristos	memset(&version, 0, sizeof(version));
135842542f5fSchristos	version.name_len = sizeof(name) - 1;
135942542f5fSchristos	version.name = name;
136042542f5fSchristos	version.date_len = sizeof(date) - 1;
136142542f5fSchristos	version.date = date;
136242542f5fSchristos
136342542f5fSchristos	if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
136442542f5fSchristos		return;
136542542f5fSchristos
136642542f5fSchristos	xf86DrvMsg(scrn->scrnIndex, X_INFO,
136742542f5fSchristos		   "Using Kernel Mode Setting driver: %s, version %d.%d.%d %s\n",
136842542f5fSchristos		   version.name,
136942542f5fSchristos		   version.version_major, version.version_minor, version.version_patchlevel,
137042542f5fSchristos		   version.date);
137142542f5fSchristos}
137242542f5fSchristos
137342542f5fSchristosstatic void describe_sna(ScrnInfoPtr scrn)
137403b705cfSriastradh{
137503b705cfSriastradh#if defined(USE_GIT_DESCRIBE)
137603b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
137703b705cfSriastradh		   "SNA compiled from %s\n", git_version);
137803b705cfSriastradh#elif defined(BUILDER_DESCRIPTION)
137903b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
138003b705cfSriastradh		   "SNA compiled: %s\n", BUILDER_DESCRIPTION);
138103b705cfSriastradh#endif
138203b705cfSriastradh#if !NDEBUG
138303b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
138403b705cfSriastradh		   "SNA compiled with assertions enabled\n");
138503b705cfSriastradh#endif
138603b705cfSriastradh#if DEBUG_SYNC
138703b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
138803b705cfSriastradh		   "SNA compiled with synchronous rendering\n");
138903b705cfSriastradh#endif
139003b705cfSriastradh#if DEBUG_MEMORY
139103b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
139203b705cfSriastradh		   "SNA compiled with memory allocation reporting enabled\n");
139303b705cfSriastradh#endif
139403b705cfSriastradh#if DEBUG_PIXMAP
139503b705cfSriastradh	xf86DrvMsg(scrn->scrnIndex, X_INFO,
139603b705cfSriastradh		   "SNA compiled with extra pixmap/damage validation\n");
139742542f5fSchristos#endif
139842542f5fSchristos#ifdef HAVE_VALGRIND
139942542f5fSchristos	xf86DrvMsg(scrn->scrnIndex, X_INFO,
140042542f5fSchristos		   "SNA compiled for use with valgrind\n");
140142542f5fSchristos	VALGRIND_PRINTF("SNA compiled for use with valgrind\n");
140203b705cfSriastradh#endif
140303b705cfSriastradh	DBG(("pixman version: %s\n", pixman_version_string()));
140442542f5fSchristos}
140542542f5fSchristos
140642542f5fSchristosBool sna_init_scrn(ScrnInfoPtr scrn, int entity_num)
140742542f5fSchristos{
140842542f5fSchristos	DBG(("%s: entity_num=%d\n", __FUNCTION__, entity_num));
140942542f5fSchristos	describe_kms(scrn);
141042542f5fSchristos	describe_sna(scrn);
141103b705cfSriastradh
141203b705cfSriastradh	scrn->PreInit = sna_pre_init;
141303b705cfSriastradh	scrn->ScreenInit = sna_screen_init;
141403b705cfSriastradh	if (!hosted()) {
141503b705cfSriastradh		scrn->SwitchMode = sna_switch_mode;
141603b705cfSriastradh		scrn->AdjustFrame = sna_adjust_frame;
141703b705cfSriastradh		scrn->EnterVT = sna_enter_vt;
141803b705cfSriastradh		scrn->LeaveVT = sna_leave_vt;
141903b705cfSriastradh		scrn->ValidMode = sna_valid_mode;
142003b705cfSriastradh		scrn->PMEvent = sna_pm_event;
142103b705cfSriastradh	} else {
142203b705cfSriastradh		scrn->EnterVT = sna_enter_vt__hosted;
142303b705cfSriastradh		scrn->LeaveVT = sna_leave_vt__hosted;
142403b705cfSriastradh	}
142503b705cfSriastradh	scrn->FreeScreen = sna_free_screen;
142603b705cfSriastradh
142703b705cfSriastradh	xf86SetEntitySharable(entity_num);
142803b705cfSriastradh	xf86SetEntityInstanceForScreen(scrn, entity_num,
142903b705cfSriastradh				       xf86GetNumEntityInstances(entity_num)-1);
143003b705cfSriastradh
143103b705cfSriastradh	sna_threads_init();
143203b705cfSriastradh
143303b705cfSriastradh	return TRUE;
143403b705cfSriastradh}
143542542f5fSchristos
143642542f5fSchristos#if HAS_DEBUG_FULL
143742542f5fSchristos_X_ATTRIBUTE_PRINTF(1, 0) void LogF(const char *f, ...)
143842542f5fSchristos{
143942542f5fSchristos	va_list ap;
144042542f5fSchristos
144142542f5fSchristos	/* As we not only may be called from any context, we may also
144242542f5fSchristos	 * be called from a thread whilst the main thread is handling
144342542f5fSchristos	 * signals, therefore we have to use the signal-safe variants
144442542f5fSchristos	 * or else we trip over false positive assertions.
144542542f5fSchristos	 */
144642542f5fSchristos
144742542f5fSchristos	va_start(ap, f);
144842542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
144942542f5fSchristos	LogVMessageVerbSigSafe(X_NONE, 1, f, ap);
145042542f5fSchristos#else
145142542f5fSchristos	LogVMessageVerb(X_NONE, 1, f, ap);
145242542f5fSchristos#endif
145342542f5fSchristos	va_end(ap);
145442542f5fSchristos}
145542542f5fSchristos#endif
1456