xf86-video-intel/src/sna/sna_driver.c

1253 lines
30 KiB
C

/**************************************************************************
Copyright 2001 VA Linux Systems Inc., Fremont, California.
Copyright © 2002 by David Dawes
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************/
/*
* Authors: Jeff Hartmann <jhartmann@valinux.com>
* Abraham van der Merwe <abraham@2d3d.co.za>
* David Dawes <dawes@xfree86.org>
* Alan Hourihane <alanh@tungstengraphics.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "sna.h"
#include "sna_module.h"
#include "sna_video.h"
#include "intel_driver.h"
#include "intel_options.h"
#include <xf86cmap.h>
#include <xf86drm.h>
#include <xf86RandR12.h>
#include <mi.h>
#include <micmap.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include "i915_drm.h"
#ifdef HAVE_VALGRIND
#include <valgrind.h>
#include <memcheck.h>
#endif
#if HAVE_DOT_GIT
#include "git_version.h"
#endif
DevPrivateKeyRec sna_pixmap_key;
DevPrivateKeyRec sna_gc_key;
DevPrivateKeyRec sna_window_key;
DevPrivateKeyRec sna_glyph_key;
DevPrivateKeyRec sna_client_key;
static void
sna_load_palette(ScrnInfoPtr scrn, int numColors, int *indices,
LOCO * colors, VisualPtr pVisual)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int p, n, i, j;
uint16_t lut_r[256], lut_g[256], lut_b[256];
DBG(("%s\n", __FUNCTION__));
for (p = 0; p < xf86_config->num_crtc; p++) {
xf86CrtcPtr crtc = xf86_config->crtc[p];
#define C(I,RGB) (colors[I].RGB << 8 | colors[I].RGB)
switch (scrn->depth) {
case 15:
for (n = 0; n < numColors; n++) {
i = indices[n];
for (j = 0; j < 8; j++) {
lut_r[8*i + j] = C(i, red);
lut_g[8*i + j] = C(i, green);
lut_b[8*i + j] = C(i, blue);
}
}
break;
case 16:
for (n = 0; n < numColors; n++) {
i = indices[n];
if (i <= 31) {
for (j = 0; j < 8; j++) {
lut_r[8*i + j] = C(i, red);
lut_b[8*i + j] = C(i, blue);
}
}
for (j = 0; j < 4; j++)
lut_g[4*i + j] = C(i, green);
}
break;
default:
for (n = 0; n < numColors; n++) {
i = indices[n];
lut_r[i] = C(i, red);
lut_g[i] = C(i, green);
lut_b[i] = C(i, blue);
}
break;
}
#undef C
/* Make the change through RandR */
#ifdef RANDR_12_INTERFACE
RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
#else
crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
#endif
}
}
static void
sna_set_fallback_mode(ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
xf86OutputPtr output = NULL;
xf86CrtcPtr crtc = NULL;
int n;
if ((unsigned)config->compat_output < config->num_output) {
output = config->output[config->compat_output];
crtc = output->crtc;
}
for (n = 0; n < config->num_output; n++)
config->output[n]->crtc = NULL;
for (n = 0; n < config->num_crtc; n++)
config->crtc[n]->enabled = FALSE;
if (output && crtc) {
DisplayModePtr mode;
output->crtc = crtc;
mode = xf86OutputFindClosestMode(output, scrn->currentMode);
if (mode &&
xf86CrtcSetModeTransform(crtc, mode, RR_Rotate_0, NULL, 0, 0)) {
crtc->desiredMode = *mode;
crtc->desiredMode.prev = crtc->desiredMode.next = NULL;
crtc->desiredMode.name = NULL;
crtc->desiredMode.PrivSize = 0;
crtc->desiredMode.PrivFlags = 0;
crtc->desiredMode.Private = NULL;
crtc->desiredRotation = RR_Rotate_0;
crtc->desiredTransformPresent = FALSE;
crtc->desiredX = 0;
crtc->desiredY = 0;
crtc->enabled = TRUE;
}
}
xf86DisableUnusedFunctions(scrn);
#ifdef RANDR_12_INTERFACE
if (get_root_window(scrn->pScreen))
xf86RandR12TellChanged(scrn->pScreen);
#endif
}
static Bool sna_set_desired_mode(struct sna *sna)
{
ScrnInfoPtr scrn = sna->scrn;
DBG(("%s\n", __FUNCTION__));
if (!xf86SetDesiredModes(scrn)) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"failed to restore desired modes on VT switch\n");
sna_set_fallback_mode(scrn);
}
sna_mode_update(sna);
return TRUE;
}
/**
* Adjust the screen pixmap for the current location of the front buffer.
* This is done at EnterVT when buffers are bound as long as the resources
* have already been created, but the first EnterVT happens before
* CreateScreenResources.
*/
static Bool sna_create_screen_resources(ScreenPtr screen)
{
struct sna *sna = to_sna_from_screen(screen);
PixmapPtr new_front;
unsigned hint;
DBG(("%s(%dx%d@%d)\n", __FUNCTION__,
screen->width, screen->height, screen->rootDepth));
assert(sna->scrn == xf86ScreenToScrn(screen));
assert(sna->scrn->pScreen == screen);
/* free the data used during miInitScreen */
free(screen->devPrivate);
screen->devPrivate = NULL;
sna_accel_create(sna);
hint = SNA_CREATE_FB;
if (sna->flags & SNA_IS_HOSTED)
hint = 0;
new_front = screen->CreatePixmap(screen,
screen->width,
screen->height,
screen->rootDepth,
hint);
if (!new_front) {
xf86DrvMsg(screen->myNum, X_ERROR,
"[intel] Unable to create front buffer %dx%d at depth %d\n",
screen->width,
screen->height,
screen->rootDepth);
return FALSE;
}
if (!sna_pixmap_force_to_gpu(new_front, MOVE_WRITE)) {
xf86DrvMsg(screen->myNum, X_ERROR,
"[intel] Failed to allocate video resources for front buffer %dx%d at depth %d\n",
screen->width,
screen->height,
screen->rootDepth);
screen->DestroyPixmap(new_front);
return FALSE;
}
screen->SetScreenPixmap(new_front);
assert(screen->GetScreenPixmap(screen) == new_front);
assert(sna->front == new_front);
screen->DestroyPixmap(new_front); /* transfer ownership to screen */
if (intel_get_master(sna->scrn)) {
xf86DrvMsg(screen->myNum, X_ERROR,
"[intel] Failed to become DRM master\n");
screen->DestroyPixmap(sna->front);
sna->front = NULL;
return FALSE;
}
/* Only preserve the fbcon, not any subsequent server regens */
if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
sna_copy_fbcon(sna);
if (!sna_set_desired_mode(sna)) {
xf86DrvMsg(screen->myNum, X_ERROR,
"[intel] Failed to set initial mode\n");
screen->DestroyPixmap(sna->front);
sna->front = NULL;
return FALSE;
}
return TRUE;
}
static void sna_selftest(void)
{
sna_damage_selftest();
}
static bool has_vsync(struct sna *sna)
{
if (sna->flags & SNA_IS_HOSTED)
return false;
return true;
}
static bool has_pageflipping(struct sna *sna)
{
drm_i915_getparam_t gp;
int v;
if (sna->flags & SNA_IS_HOSTED)
return false;
v = 0;
VG_CLEAR(gp);
gp.param = I915_PARAM_HAS_PAGEFLIPPING;
gp.value = &v;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp))
return false;
VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v)));
return v > 0;
}
static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
{
#if HAS_PIXMAP_SHARING && defined(DRM_CAP_PRIME)
uint64_t value;
scrn->capabilities = 0;
if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0) {
if (value & DRM_PRIME_CAP_EXPORT)
scrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SinkOffload;
if (value & DRM_PRIME_CAP_IMPORT)
scrn->capabilities |= RR_Capability_SinkOutput;
}
#endif
}
static int
namecmp(const char *s1, const char *s2)
{
char c1, c2;
if (!s1 || *s1 == 0) {
if (!s2 || *s2 == 0)
return 0;
else
return 1;
}
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
s1++;
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
s2++;
c1 = isupper(*s1) ? tolower(*s1) : *s1;
c2 = isupper(*s2) ? tolower(*s2) : *s2;
while (c1 == c2) {
if (c1 == '\0')
return 0;
s1++;
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
s1++;
s2++;
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
s2++;
c1 = isupper(*s1) ? tolower(*s1) : *s1;
c2 = isupper(*s2) ? tolower(*s2) : *s2;
}
return c1 - c2;
}
static Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
{
const char *str = xf86GetOptValString(sna->Options, id);
if (str == NULL)
return val;
if (*str == '\0')
return TRUE;
if (namecmp(str, "1") == 0)
return TRUE;
if (namecmp(str, "on") == 0)
return TRUE;
if (namecmp(str, "true") == 0)
return TRUE;
if (namecmp(str, "yes") == 0)
return TRUE;
if (namecmp(str, "0") == 0)
return FALSE;
if (namecmp(str, "off") == 0)
return FALSE;
if (namecmp(str, "false") == 0)
return FALSE;
if (namecmp(str, "no") == 0)
return FALSE;
return val;
}
static Bool fb_supports_depth(int fd, int depth)
{
struct drm_i915_gem_create create;
struct drm_mode_fb_cmd fb;
Bool ret;
VG_CLEAR(create);
create.handle = 0;
create.size = 4096;
if (drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create))
return FALSE;
VG_CLEAR(fb);
fb.width = 64;
fb.height = 16;
fb.pitch = 256;
fb.bpp = depth <= 8 ? 8 : depth <= 16 ? 16 : 32;
fb.depth = depth;
fb.handle = create.handle;
ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB, &fb) == 0;
drmModeRmFB(fd, fb.fb_id);
(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
return ret;
}
/**
* This is called before ScreenInit to do any require probing of screen
* configuration.
*
* This code generally covers probing, module loading, option handling
* card mapping, and RandR setup.
*
* Since xf86InitialConfiguration ends up requiring that we set video modes
* in order to detect configuration, we end up having to do a lot of driver
* setup (talking to the DRM, mapping the device, etc.) in this function.
* As a result, we want to set up that server initialization once rather
* that doing it per generation.
*/
static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
{
struct sna *sna;
char buf[1024];
rgb defaultWeight = { 0, 0, 0 };
EntityInfoPtr pEnt;
int preferred_depth;
Gamma zeros = { 0.0, 0.0, 0.0 };
int fd;
DBG(("%s flags=%x, numEntities=%d\n",
__FUNCTION__, flags, scrn->numEntities));
if (scrn->numEntities != 1)
return FALSE;
pEnt = xf86GetEntityInfo(scrn->entityList[0]);
if (pEnt == NULL)
return FALSE;
if (pEnt->location.type != BUS_PCI
#ifdef XSERVER_PLATFORM_BUS
&& pEnt->location.type != BUS_PLATFORM
#endif
)
return FALSE;
if (flags & PROBE_DETECT)
return TRUE;
sna_selftest();
if (((uintptr_t)scrn->driverPrivate) & 1) {
if (posix_memalign((void **)&sna, 4096, sizeof(*sna)))
return FALSE;
memset(sna, 0, sizeof(*sna)); /* should be unnecessary */
sna->info = (void *)((uintptr_t)scrn->driverPrivate & ~1);
scrn->driverPrivate = sna;
sna->cpu_features = sna_cpu_detect();
sna->acpi.fd = sna_acpi_open();
}
sna = to_sna(scrn);
sna->scrn = scrn;
sna->pEnt = pEnt;
sna->flags = 0;
scrn->displayWidth = 640; /* default it */
scrn->monitor = scrn->confScreen->monitor;
scrn->progClock = TRUE;
scrn->rgbBits = 8;
fd = intel_get_device(scrn);
if (fd == -1) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Failed to claim DRM device.\n");
goto cleanup;
}
/* Sanity check */
if (hosted() && (sna->flags & SNA_IS_HOSTED) == 0) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Failed to setup hosted device.\n");
goto cleanup;
}
intel_detect_chipset(scrn, pEnt);
xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
sna_cpu_features_to_string(sna->cpu_features, buf));
preferred_depth = sna->info->gen < 030 ? 15 : 24;
if (!fb_supports_depth(fd, preferred_depth))
preferred_depth = 24;
if (!xf86SetDepthBpp(scrn, preferred_depth, 0, 0,
Support32bppFb |
SupportConvert24to32 | PreferConvert24to32))
goto cleanup;
switch (scrn->depth) {
case 8:
case 15:
case 16:
case 24:
case 30:
if ((sna->flags & SNA_IS_HOSTED) ||
fb_supports_depth(fd, scrn->depth))
break;
default:
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Given depth (%d) is not supported by the Intel driver and this chipset.\n",
scrn->depth);
goto cleanup;
}
xf86PrintDepthBpp(scrn);
if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
goto cleanup;
if (!xf86SetDefaultVisual(scrn, -1))
goto cleanup;
sna->Options = intel_options_get(scrn);
if (sna->Options == NULL)
goto cleanup;
sna_setup_capabilities(scrn, fd);
kgem_init(&sna->kgem, fd,
xf86GetPciInfoForEntity(pEnt->index),
sna->info->gen);
if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
!sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
"Disabling hardware acceleration.\n");
sna->kgem.wedged = true;
}
/* Enable tiling by default */
sna->tiling = SNA_TILING_ALL;
/* Allow user override if they set a value */
if (!xf86ReturnOptValBool(sna->Options, OPTION_TILING_2D, TRUE))
sna->tiling &= ~SNA_TILING_2D;
if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
sna->tiling &= ~SNA_TILING_FB;
if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
sna->flags |= SNA_NO_WAIT;
DBG(("%s: swapbuffer wait? %s\n", __FUNCTION__, sna->flags & SNA_NO_WAIT ? "disabled" : "enabled"));
if (!has_vsync(sna) ||
!xf86ReturnOptValBool(sna->Options, OPTION_VSYNC, TRUE))
sna->flags |= SNA_NO_VSYNC;
DBG(("%s: vsync? %s\n", __FUNCTION__, sna->flags & SNA_NO_VSYNC ? "disabled" : "enabled"));
if (!has_pageflipping(sna) ||
!xf86ReturnOptValBool(sna->Options, OPTION_PAGEFLIP, TRUE))
sna->flags |= SNA_NO_FLIP;
DBG(("%s: page flips? %s\n", __FUNCTION__, sna->flags & SNA_NO_FLIP ? "disabled" : "enabled"));
if ((sna->flags & (SNA_NO_VSYNC | SNA_NO_FLIP | SNA_NO_WAIT)) == 0 &&
xf86ReturnOptValBool(sna->Options, OPTION_TRIPLE_BUFFER, TRUE))
sna->flags |= SNA_TRIPLE_BUFFER;
DBG(("%s: triple buffer? %s\n", __FUNCTION__, sna->flags & SNA_TRIPLE_BUFFER ? "enabled" : "disabled"));
if ((sna->flags & (SNA_NO_VSYNC | SNA_NO_FLIP)) == 0 &&
xf86ReturnOptValBool(sna->Options, OPTION_TEAR_FREE, FALSE))
sna->flags |= SNA_TEAR_FREE;
if (xf86ReturnOptValBool(sna->Options, OPTION_CRTC_PIXMAPS, FALSE))
sna->flags |= SNA_FORCE_SHADOW;
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
sna->tiling & SNA_TILING_FB ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Pixmaps %s\n",
sna->tiling & SNA_TILING_2D ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "\"Tear free\" %sabled\n",
sna->flags & SNA_TEAR_FREE ? "en" : "dis");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Forcing per-crtc-pixmaps? %s\n",
sna->flags & SNA_FORCE_SHADOW ? "yes" : "no");
if (sna->tiling != SNA_TILING_ALL)
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"Tiling disabled, expect poor performance and increased power consumption.\n");
if (!sna_mode_pre_init(scrn, sna)) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"No outputs and no modes.\n");
goto cleanup;
}
scrn->currentMode = scrn->modes;
xf86SetGamma(scrn, zeros);
xf86SetDpi(scrn, 0, 0);
sna->dri_available = false;
if (sna_option_cast_to_bool(sna, OPTION_DRI, TRUE))
sna->dri_available = !!xf86LoadSubModule(scrn, "dri2");
sna_acpi_init(sna);
return TRUE;
cleanup:
scrn->driverPrivate = (void *)((uintptr_t)sna->info | 1);
free(sna);
return FALSE;
}
static void
sna_block_handler(BLOCKHANDLER_ARGS_DECL)
{
#ifndef XF86_SCRN_INTERFACE
struct sna *sna = to_sna(xf86Screens[arg]);
#else
struct sna *sna = to_sna_from_screen(arg);
#endif
struct timeval **tv = timeout;
DBG(("%s (tv=%ld.%06ld)\n", __FUNCTION__,
*tv ? (*tv)->tv_sec : -1, *tv ? (*tv)->tv_usec : 0));
sna->BlockHandler(BLOCKHANDLER_ARGS);
if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec))
sna_accel_block_handler(sna, tv);
}
static void
sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
{
#ifndef XF86_SCRN_INTERFACE
struct sna *sna = to_sna(xf86Screens[arg]);
#else
struct sna *sna = to_sna_from_screen(arg);
#endif
DBG(("%s\n", __FUNCTION__));
/* despite all appearances, result is just a signed int */
if ((int)result < 0)
return;
sna_acpi_wakeup(sna, read_mask);
sna->WakeupHandler(WAKEUPHANDLER_ARGS);
sna_accel_wakeup_handler(sna);
if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask))
sna_mode_wakeup(sna);
}
#if HAVE_UDEV
static void
sna_handle_uevents(int fd, void *closure)
{
ScrnInfoPtr scrn = closure;
struct sna *sna = to_sna(scrn);
struct udev_device *dev;
const char *hotplug;
struct stat s;
dev_t udev_devnum;
DBG(("%s\n", __FUNCTION__));
dev = udev_monitor_receive_device(sna->uevent_monitor);
if (!dev)
return;
udev_devnum = udev_device_get_devnum(dev);
if (fstat(sna->kgem.fd, &s)) {
udev_device_unref(dev);
return;
}
/*
* Check to make sure this event is directed at our
* device (by comparing dev_t values), then make
* sure it's a hotplug event (HOTPLUG=1)
*/
hotplug = udev_device_get_property_value(dev, "HOTPLUG");
if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
hotplug && atoi(hotplug) == 1) {
DBG(("%s: hotplug event (vtSema?=%d)\n",
__FUNCTION__, sna->scrn->vtSema));
if (sna->scrn->vtSema) {
sna_mode_update(sna);
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
} else
sna->flags |= SNA_REPROBE;
}
udev_device_unref(dev);
}
static void
sna_uevent_init(ScrnInfoPtr scrn)
{
struct sna *sna = to_sna(scrn);
struct udev *u;
struct udev_monitor *mon;
Bool hotplug;
MessageType from = X_CONFIG;
if (sna->flags & SNA_IS_HOSTED)
return;
DBG(("%s\n", __FUNCTION__));
/* RandR will be disabled if Xinerama is active, and so generating
* RR hotplug events is then verboten.
*/
if (!dixPrivateKeyRegistered(rrPrivKey))
return;
if (!xf86GetOptValBool(sna->Options, OPTION_HOTPLUG, &hotplug))
from = X_DEFAULT, hotplug = TRUE;
xf86DrvMsg(scrn->scrnIndex, from, "hotplug detection: \"%s\"\n",
hotplug ? "enabled" : "disabled");
if (!hotplug)
return;
u = udev_new();
if (!u)
return;
mon = udev_monitor_new_from_netlink(u, "udev");
if (!mon) {
udev_unref(u);
return;
}
if (udev_monitor_filter_add_match_subsystem_devtype(mon,
"drm", "drm_minor") < 0 ||
udev_monitor_enable_receiving(mon) < 0)
{
udev_monitor_unref(mon);
udev_unref(u);
return;
}
sna->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
sna_handle_uevents, scrn);
if (!sna->uevent_handler) {
udev_monitor_unref(mon);
udev_unref(u);
return;
}
sna->uevent_monitor = mon;
DBG(("%s: installed uvent handler\n", __FUNCTION__));
}
static void
sna_uevent_fini(ScrnInfoPtr scrn)
{
struct sna *sna = to_sna(scrn);
struct udev *u;
if (sna->uevent_handler == NULL)
return;
xf86RemoveGeneralHandler(sna->uevent_handler);
u = udev_monitor_get_udev(sna->uevent_monitor);
udev_monitor_unref(sna->uevent_monitor);
udev_unref(u);
sna->uevent_handler = NULL;
sna->uevent_monitor = NULL;
DBG(("%s: removed uvent handler\n", __FUNCTION__));
}
#else
static void sna_uevent_init(ScrnInfoPtr scrn) { }
static void sna_uevent_fini(ScrnInfoPtr scrn) { }
#endif /* HAVE_UDEV */
static void sna_leave_vt(VT_FUNC_ARGS_DECL)
{
SCRN_INFO_PTR(arg);
DBG(("%s\n", __FUNCTION__));
xf86_hide_cursors(scrn);
sna_mode_reset(to_sna(scrn));
if (intel_put_master(scrn))
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"drmDropMaster failed: %s\n", strerror(errno));
}
static Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
struct sna *sna = to_sna(scrn);
DBG(("%s\n", __FUNCTION__));
/* XXX Note that we will leak kernel resources if !vtSema */
xf86_hide_cursors(scrn);
sna_uevent_fini(scrn);
sna_mode_close(sna);
if (sna->dri_open) {
sna_dri_close(sna, screen);
sna->dri_open = false;
}
if (sna->front) {
screen->DestroyPixmap(sna->front);
sna->front = NULL;
}
if (scrn->vtSema) {
intel_put_master(scrn);
scrn->vtSema = FALSE;
}
xf86_cursors_fini(screen);
return sna->CloseScreen(CLOSE_SCREEN_ARGS);
}
static Bool sna_late_close_screen(CLOSE_SCREEN_ARGS_DECL)
{
struct sna *sna = to_sna_from_screen(screen);
DepthPtr depths;
int d;
DBG(("%s\n", __FUNCTION__));
sna_accel_close(sna);
depths = screen->allowedDepths;
for (d = 0; d < screen->numDepths; d++)
free(depths[d].vids);
free(depths);
free(screen->visuals);
return TRUE;
}
static Bool
sna_register_all_privates(void)
{
#if HAS_DIXREGISTERPRIVATEKEY
if (!dixRegisterPrivateKey(&sna_pixmap_key, PRIVATE_PIXMAP,
3*sizeof(void *)))
return FALSE;
if (!dixRegisterPrivateKey(&sna_gc_key, PRIVATE_GC,
sizeof(FbGCPrivate)))
return FALSE;
if (!dixRegisterPrivateKey(&sna_glyph_key, PRIVATE_GLYPH,
sizeof(struct sna_glyph)))
return FALSE;
if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
3*sizeof(void *)))
return FALSE;
if (!dixRegisterPrivateKey(&sna_client_key, PRIVATE_CLIENT,
sizeof(struct sna_client)))
return FALSE;
#else
if (!dixRequestPrivate(&sna_pixmap_key, 3*sizeof(void *)))
return FALSE;
if (!dixRequestPrivate(&sna_gc_key, sizeof(FbGCPrivate)))
return FALSE;
if (!dixRequestPrivate(&sna_glyph_key, sizeof(struct sna_glyph)))
return FALSE;
if (!dixRequestPrivate(&sna_window_key, 3*sizeof(void *)))
return FALSE;
if (!dixRequestPrivate(&sna_client_key, sizeof(struct sna_client)))
return FALSE;
#endif
return TRUE;
}
static size_t
agp_aperture_size(struct pci_device *dev, int gen)
{
return dev->regions[gen < 030 ? 0 : 2].size;
}
static Bool
sna_screen_init(SCREEN_INIT_ARGS_DECL)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
struct sna *sna = to_sna(scrn);
struct pci_device *pci;
VisualPtr visuals;
DepthPtr depths;
int nvisuals;
int ndepths;
int rootdepth;
VisualID defaultVisual;
DBG(("%s\n", __FUNCTION__));
assert(sna->scrn == scrn);
assert(scrn->pScreen == NULL); /* set afterwards */
assert(sna->freed_pixmap == NULL);
if (!sna_register_all_privates())
return FALSE;
pci = xf86GetPciInfoForEntity(sna->pEnt->index);
if (pci != NULL)
scrn->videoRam = agp_aperture_size(pci, sna->kgem.gen) / 1024;
else
scrn->videoRam = 256;
miClearVisualTypes();
if (!miSetVisualTypes(scrn->depth,
miGetDefaultVisualMask(scrn->depth),
scrn->rgbBits, scrn->defaultVisual))
return FALSE;
if (!miSetPixmapDepths())
return FALSE;
rootdepth = 0;
if (!miInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &rootdepth,
&defaultVisual,
((unsigned long)1 << (scrn->bitsPerPixel - 1)),
8, -1))
return FALSE;
if (!miScreenInit(screen, NULL,
scrn->virtualX, scrn->virtualY,
scrn->xDpi, scrn->yDpi, 0,
rootdepth, ndepths, depths,
defaultVisual, nvisuals, visuals))
return FALSE;
if (scrn->bitsPerPixel > 8) {
/* Fixup RGB ordering */
VisualPtr visual = screen->visuals + screen->numVisuals;
while (--visual >= screen->visuals) {
if ((visual->class | DynamicClass) == DirectColor) {
visual->offsetRed = scrn->offset.red;
visual->offsetGreen = scrn->offset.green;
visual->offsetBlue = scrn->offset.blue;
visual->redMask = scrn->mask.red;
visual->greenMask = scrn->mask.green;
visual->blueMask = scrn->mask.blue;
}
}
}
assert(screen->CloseScreen == NULL);
screen->CloseScreen = sna_late_close_screen;
if (!sna_accel_init(screen, sna)) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Hardware acceleration initialization failed\n");
return FALSE;
}
xf86SetBlackWhitePixels(screen);
xf86SetBackingStore(screen);
xf86SetSilkenMouse(screen);
if (!miDCInitialize(screen, xf86GetPointerScreenFuncs()))
return FALSE;
if ((sna->flags & SNA_IS_HOSTED) == 0 &&
xf86_cursors_init(screen, SNA_CURSOR_X, SNA_CURSOR_Y,
HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
HARDWARE_CURSOR_INVERT_MASK |
HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
HARDWARE_CURSOR_UPDATE_UNHIDDEN |
HARDWARE_CURSOR_ARGB))
xf86DrvMsg(scrn->scrnIndex, X_INFO, "HW Cursor enabled\n");
/* Must force it before EnterVT, so we are in control of VT and
* later memory should be bound when allocating, e.g rotate_mem */
scrn->vtSema = TRUE;
sna->BlockHandler = screen->BlockHandler;
screen->BlockHandler = sna_block_handler;
sna->WakeupHandler = screen->WakeupHandler;
screen->WakeupHandler = sna_wakeup_handler;
screen->SaveScreen = xf86SaveScreen;
screen->CreateScreenResources = sna_create_screen_resources;
sna->CloseScreen = screen->CloseScreen;
screen->CloseScreen = sna_early_close_screen;
if (!xf86CrtcScreenInit(screen))
return FALSE;
xf86RandR12SetRotations(screen, RR_Rotate_All | RR_Reflect_All);
xf86RandR12SetTransformSupport(screen, TRUE);
if (!miCreateDefColormap(screen))
return FALSE;
if (!xf86HandleColormaps(screen, 256, 8, sna_load_palette, NULL,
CMAP_RELOAD_ON_MODE_SWITCH |
CMAP_PALETTED_TRUECOLOR)) {
return FALSE;
}
xf86DPMSInit(screen, xf86DPMSSet, 0);
sna_video_init(sna, screen);
if (sna->dri_available)
sna->dri_open = sna_dri_open(sna, screen);
if (sna->dri_open)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"direct rendering: DRI2 Enabled\n");
if (serverGeneration == 1)
xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
sna->suspended = FALSE;
sna_uevent_init(scrn);
return TRUE;
}
static void sna_adjust_frame(ADJUST_FRAME_ARGS_DECL)
{
SCRN_INFO_PTR(arg);
DBG(("%s(%d, %d)\n", __FUNCTION__, x, y));
sna_mode_adjust_frame(to_sna(scrn), x, y);
}
static void sna_free_screen(FREE_SCREEN_ARGS_DECL)
{
SCRN_INFO_PTR(arg);
struct sna *sna = to_sna(scrn);
DBG(("%s\n", __FUNCTION__));
if ((uintptr_t)sna & 1)
return;
scrn->driverPrivate = (void *)((uintptr_t)sna->info | 1);
sna_mode_fini(sna);
sna_acpi_fini(sna);
free(sna);
intel_put_device(scrn);
}
static Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
{
SCRN_INFO_PTR(arg);
struct sna *sna = to_sna(scrn);
DBG(("%s\n", __FUNCTION__));
if (intel_get_master(scrn))
return FALSE;
if (!sna_set_desired_mode(sna))
return FALSE;
if (sna->flags & SNA_REPROBE) {
DBG(("%s: reporting deferred hotplug event\n",
__FUNCTION__));
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
sna->flags &= ~SNA_REPROBE;
}
return TRUE;
}
static Bool sna_switch_mode(SWITCH_MODE_ARGS_DECL)
{
SCRN_INFO_PTR(arg);
DBG(("%s\n", __FUNCTION__));
return xf86SetSingleMode(scrn, mode, RR_Rotate_0);
}
static ModeStatus
sna_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
{
return MODE_OK;
}
#ifndef SUSPEND_SLEEP
#define SUSPEND_SLEEP 0
#endif
#ifndef RESUME_SLEEP
#define RESUME_SLEEP 0
#endif
/*
* This function is only required if we need to do anything differently from
* DoApmEvent() in common/xf86PM.c, including if we want to see events other
* than suspend/resume.
*/
static Bool sna_pm_event(SCRN_ARG_TYPE arg, pmEvent event, Bool undo)
{
SCRN_INFO_PTR(arg);
struct sna *sna = to_sna(scrn);
DBG(("%s\n", __FUNCTION__));
switch (event) {
case XF86_APM_SYS_SUSPEND:
case XF86_APM_CRITICAL_SUSPEND: /*do we want to delay a critical suspend? */
case XF86_APM_USER_SUSPEND:
case XF86_APM_SYS_STANDBY:
case XF86_APM_USER_STANDBY:
if (!undo && !sna->suspended) {
scrn->LeaveVT(VT_FUNC_ARGS(0));
sna->suspended = TRUE;
sleep(SUSPEND_SLEEP);
} else if (undo && sna->suspended) {
sleep(RESUME_SLEEP);
scrn->EnterVT(VT_FUNC_ARGS(0));
sna->suspended = FALSE;
}
break;
case XF86_APM_STANDBY_RESUME:
case XF86_APM_NORMAL_RESUME:
case XF86_APM_CRITICAL_RESUME:
if (sna->suspended) {
sleep(RESUME_SLEEP);
scrn->EnterVT(VT_FUNC_ARGS(0));
sna->suspended = FALSE;
/*
* Turn the screen saver off when resuming. This seems to be
* needed to stop xscreensaver kicking in (when used).
*
* XXX DoApmEvent() should probably call this just like
* xf86VTSwitch() does. Maybe do it here only in 4.2
* compatibility mode.
*/
SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
}
break;
/* This is currently used for ACPI */
case XF86_APM_CAPABILITY_CHANGED:
SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
break;
default:
ErrorF("sna_pm_event: received APM event %d\n", event);
}
return TRUE;
}
static Bool sna_enter_vt__hosted(VT_FUNC_ARGS_DECL)
{
return TRUE;
}
static void sna_leave_vt__hosted(VT_FUNC_ARGS_DECL)
{
}
Bool sna_init_scrn(ScrnInfoPtr scrn, int entity_num)
{
DBG(("%s: entity_num=%d\n", __FUNCTION__, entity_num));
#if defined(USE_GIT_DESCRIBE)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled from %s\n", git_version);
#elif defined(BUILDER_DESCRIPTION)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled: %s\n", BUILDER_DESCRIPTION);
#endif
#if !NDEBUG
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled with assertions enabled\n");
#endif
#if DEBUG_SYNC
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled with synchronous rendering\n");
#endif
#if DEBUG_MEMORY
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled with memory allocation reporting enabled\n");
#endif
#if DEBUG_PIXMAP
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"SNA compiled with extra pixmap/damage validation\n");
#endif
DBG(("pixman version: %s\n", pixman_version_string()));
scrn->PreInit = sna_pre_init;
scrn->ScreenInit = sna_screen_init;
if (!hosted()) {
scrn->SwitchMode = sna_switch_mode;
scrn->AdjustFrame = sna_adjust_frame;
scrn->EnterVT = sna_enter_vt;
scrn->LeaveVT = sna_leave_vt;
scrn->ValidMode = sna_valid_mode;
scrn->PMEvent = sna_pm_event;
} else {
scrn->EnterVT = sna_enter_vt__hosted;
scrn->LeaveVT = sna_leave_vt__hosted;
}
scrn->FreeScreen = sna_free_screen;
xf86SetEntitySharable(entity_num);
xf86SetEntityInstanceForScreen(scrn, entity_num,
xf86GetNumEntityInstances(entity_num)-1);
sna_threads_init();
return TRUE;
}