summaryrefslogtreecommitdiff
path: root/src/sna/sna_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sna/sna_driver.c')
-rw-r--r--src/sna/sna_driver.c925
1 files changed, 925 insertions, 0 deletions
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
new file mode 100644
index 00000000..b0df9aa5
--- /dev/null
+++ b/src/sna/sna_driver.c
@@ -0,0 +1,925 @@
+/**************************************************************************
+
+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 "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Priv.h"
+#include "xf86cmap.h"
+#include "compiler.h"
+#include "mibstore.h"
+#include "vgaHW.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include "shadowfb.h"
+#include <X11/extensions/randr.h>
+#include "fb.h"
+#include "miscstruct.h"
+#include "dixstruct.h"
+#include "xf86xv.h"
+#include <X11/extensions/Xv.h>
+#include "sna.h"
+#include "sna_module.h"
+#include "sna_video.h"
+
+#include "intel_driver.h"
+
+#include <sys/ioctl.h>
+#include "i915_drm.h"
+
+static OptionInfoRec sna_options[] = {
+ {OPTION_TILING_FB, "LinearFramebuffer", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_TILING_2D, "Tiling", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_THROTTLE, "Throttle", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_RELAXED_FENCING, "UseRelaxedFencing", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_VMAP, "UseVmap", OPTV_BOOLEAN, {0}, TRUE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+
+static Bool sna_enter_vt(int scrnIndex, int flags);
+
+/* temporary */
+extern void xf86SetCursor(ScreenPtr screen, CursorPtr pCurs, int x, int y);
+
+const OptionInfoRec *sna_available_options(int chipid, int busid)
+{
+ return sna_options;
+}
+
+static void
+sna_load_palette(ScrnInfoPtr scrn, int numColors, int *indices,
+ LOCO * colors, VisualPtr pVisual)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int i, j, index;
+ int p;
+ uint16_t lut_r[256], lut_g[256], lut_b[256];
+
+ for (p = 0; p < xf86_config->num_crtc; p++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[p];
+
+ switch (scrn->depth) {
+ case 15:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ for (j = 0; j < 8; j++) {
+ lut_r[index * 8 + j] =
+ colors[index].red << 8;
+ lut_g[index * 8 + j] =
+ colors[index].green << 8;
+ lut_b[index * 8 + j] =
+ colors[index].blue << 8;
+ }
+ }
+ break;
+ case 16:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+
+ if (index <= 31) {
+ for (j = 0; j < 8; j++) {
+ lut_r[index * 8 + j] =
+ colors[index].red << 8;
+ lut_b[index * 8 + j] =
+ colors[index].blue << 8;
+ }
+ }
+
+ for (j = 0; j < 4; j++) {
+ lut_g[index * 4 + j] =
+ colors[index].green << 8;
+ }
+ }
+ break;
+ default:
+ for (i = 0; i < numColors; i++) {
+ index = indices[i];
+ lut_r[index] = colors[index].red << 8;
+ lut_g[index] = colors[index].green << 8;
+ lut_b[index] = colors[index].blue << 8;
+ }
+ break;
+ }
+
+ /* 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
+ }
+}
+
+/**
+ * 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)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct sna *sna = to_sna(scrn);
+
+ free(screen->devPrivate);
+ screen->devPrivate = NULL;
+
+ sna->front = screen->CreatePixmap(screen,
+ screen->width,
+ screen->height,
+ screen->rootDepth,
+ SNA_CREATE_FB);
+ if (!sna->front)
+ return FALSE;
+
+ if (!sna_pixmap_force_to_gpu(sna->front))
+ goto cleanup_front;
+
+ screen->SetScreenPixmap(sna->front);
+
+ if (!sna_accel_create(sna))
+ goto cleanup_front;
+
+ if (!sna_enter_vt(screen->myNum, 0))
+ goto cleanup_front;
+
+ return TRUE;
+
+cleanup_front:
+ screen->DestroyPixmap(sna->front);
+ sna->front = NULL;
+ return FALSE;
+}
+
+static void PreInitCleanup(ScrnInfoPtr scrn)
+{
+ if (!scrn || !scrn->driverPrivate)
+ return;
+
+ free(scrn->driverPrivate);
+ scrn->driverPrivate = NULL;
+}
+
+static void sna_check_chipset_option(ScrnInfoPtr scrn)
+{
+ struct sna *sna = to_sna(scrn);
+ MessageType from = X_PROBED;
+
+ intel_detect_chipset(scrn, sna->PciInfo, &sna->chipset);
+
+ /* Set the Chipset and ChipRev, allowing config file entries to override. */
+ if (sna->pEnt->device->chipset && *sna->pEnt->device->chipset) {
+ scrn->chipset = sna->pEnt->device->chipset;
+ from = X_CONFIG;
+ } else if (sna->pEnt->device->chipID >= 0) {
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ sna->pEnt->device->chipID);
+ from = X_CONFIG;
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "ChipID override: 0x%04X\n",
+ sna->pEnt->device->chipID);
+ DEVICE_ID(sna->PciInfo) = sna->pEnt->device->chipID;
+ } else {
+ from = X_PROBED;
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ DEVICE_ID(sna->PciInfo));
+ }
+
+ if (sna->pEnt->device->chipRev >= 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ sna->pEnt->device->chipRev);
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from, "Chipset: \"%s\"\n",
+ (scrn->chipset != NULL) ? scrn->chipset : "Unknown i8xx");
+}
+
+static Bool sna_get_early_options(ScrnInfoPtr scrn)
+{
+ struct sna *sna = to_sna(scrn);
+
+ /* Process the options */
+ xf86CollectOptions(scrn, NULL);
+ if (!(sna->Options = malloc(sizeof(sna_options))))
+ return FALSE;
+
+ memcpy(sna->Options, sna_options, sizeof(sna_options));
+ xf86ProcessOptions(scrn->scrnIndex, scrn->options, sna->Options);
+
+ return TRUE;
+}
+
+static int sna_open_drm_master(ScrnInfoPtr scrn)
+{
+ struct sna *sna = to_sna(scrn);
+ struct pci_device *dev = sna->PciInfo;
+ drmSetVersion sv;
+ struct drm_i915_getparam gp;
+ int err, val;
+ char busid[20];
+ int fd;
+
+ snprintf(busid, sizeof(busid), "pci:%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+
+ fd = drmOpen("i915", busid);
+ if (fd == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] Failed to open DRM device for %s: %s\n",
+ busid, strerror(errno));
+ return -1;
+ }
+
+ /* Check that what we opened was a master or a master-capable FD,
+ * by setting the version of the interface we'll use to talk to it.
+ * (see DRIOpenDRMMaster() in DRI1)
+ */
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 1;
+ sv.drm_dd_major = -1;
+ sv.drm_dd_minor = -1;
+ err = drmSetInterfaceVersion(fd, &sv);
+ if (err != 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] failed to set drm interface version.\n");
+ drmClose(fd);
+ return -1;
+ }
+
+ val = FALSE;
+ gp.param = I915_PARAM_HAS_BLT;
+ gp.value = &val;
+ if (drmCommandWriteRead(fd, DRM_I915_GETPARAM,
+ &gp, sizeof(gp))) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to detect BLT. Kernel 2.6.37 required.\n");
+ drmClose(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static void sna_close_drm_master(struct sna *sna)
+{
+ if (sna && sna->kgem.fd > 0) {
+ drmClose(sna->kgem.fd);
+ sna->kgem.fd = -1;
+ }
+}
+
+static void sna_selftest(void)
+{
+ sna_damage_selftest();
+}
+
+
+/**
+ * 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;
+ rgb defaultWeight = { 0, 0, 0 };
+ EntityInfoPtr pEnt;
+ int flags24;
+ Gamma zeros = { 0.0, 0.0, 0.0 };
+ int fd;
+
+ sna_selftest();
+
+ if (scrn->numEntities != 1)
+ return FALSE;
+
+ pEnt = xf86GetEntityInfo(scrn->entityList[0]);
+
+ if (flags & PROBE_DETECT)
+ return TRUE;
+
+ sna = to_sna(scrn);
+ if (sna == NULL) {
+ sna = xnfcalloc(sizeof(struct sna), 1);
+ if (sna == NULL)
+ return FALSE;
+
+ scrn->driverPrivate = sna;
+ }
+ sna->scrn = scrn;
+ sna->pEnt = pEnt;
+
+ scrn->displayWidth = 640; /* default it */
+
+ if (sna->pEnt->location.type != BUS_PCI)
+ return FALSE;
+
+ sna->PciInfo = xf86GetPciInfoForEntity(sna->pEnt->index);
+
+ fd = sna_open_drm_master(scrn);
+ if (fd == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to become DRM master.\n");
+ return FALSE;
+ }
+
+ scrn->monitor = scrn->confScreen->monitor;
+ scrn->progClock = TRUE;
+ scrn->rgbBits = 8;
+
+ flags24 = Support32bppFb | PreferConvert24to32 | SupportConvert24to32;
+
+ if (!xf86SetDepthBpp(scrn, 0, 0, 0, flags24))
+ return FALSE;
+
+ switch (scrn->depth) {
+ case 8:
+ case 15:
+ case 16:
+ case 24:
+ break;
+ default:
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by Intel driver\n",
+ scrn->depth);
+ return FALSE;
+ }
+ xf86PrintDepthBpp(scrn);
+
+ if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
+ return FALSE;
+ if (!xf86SetDefaultVisual(scrn, -1))
+ return FALSE;
+
+ sna->mode.cpp = scrn->bitsPerPixel / 8;
+
+ if (!sna_get_early_options(scrn))
+ return FALSE;
+
+ sna_check_chipset_option(scrn);
+ kgem_init(&sna->kgem, fd, sna->chipset.info->gen);
+ if (!xf86ReturnOptValBool(sna->Options,
+ OPTION_RELAXED_FENCING,
+ sna->kgem.has_relaxed_fencing)) {
+ xf86DrvMsg(scrn->scrnIndex,
+ sna->kgem.has_relaxed_fencing ? X_CONFIG : X_PROBED,
+ "Disabling use of relaxed fencing\n");
+ sna->kgem.has_relaxed_fencing = 0;
+ }
+ if (!xf86ReturnOptValBool(sna->Options,
+ OPTION_VMAP,
+ sna->kgem.has_vmap)) {
+ xf86DrvMsg(scrn->scrnIndex,
+ sna->kgem.has_vmap ? X_CONFIG : X_PROBED,
+ "Disabling use of vmap\n");
+ sna->kgem.has_vmap = 0;
+ }
+
+ /* 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;
+
+ sna->flags = 0;
+ if (!xf86ReturnOptValBool(sna->Options, OPTION_THROTTLE, TRUE))
+ sna->flags |= SNA_NO_THROTTLE;
+ if (xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
+ sna->flags |= SNA_SWAP_WAIT;
+
+ 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, "3D buffers %s\n",
+ sna->tiling & SNA_TILING_3D ? "tiled" : "linear");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n",
+ sna->flags & SNA_SWAP_WAIT ? "en" : "dis");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Throttling %sabled\n",
+ sna->flags & SNA_NO_THROTTLE ? "dis" : "en");
+
+ if (!sna_mode_pre_init(scrn, sna)) {
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ if (!xf86SetGamma(scrn, zeros)) {
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ if (scrn->modes == NULL) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR, "No modes.\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+ scrn->currentMode = scrn->modes;
+
+ /* Set display resolution */
+ xf86SetDpi(scrn, 0, 0);
+
+ /* Load the required sub modules */
+ if (!xf86LoadSubModule(scrn, "fb")) {
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ /* Load the dri2 module if requested. */
+ xf86LoadSubModule(scrn, "dri2");
+
+ return sna_accel_pre_init(sna);
+}
+
+/**
+ * Intialiazes the hardware for the 3D pipeline use in the 2D driver.
+ *
+ * Some state caching is performed to avoid redundant state emits. This
+ * function is also responsible for marking the state as clobbered for DRI
+ * clients.
+ */
+static void
+sna_block_handler(int i, pointer data, pointer timeout, pointer read_mask)
+{
+ ScreenPtr screen = screenInfo.screens[i];
+ ScrnInfoPtr scrn = xf86Screens[i];
+ struct sna *sna = to_sna(scrn);
+
+ screen->BlockHandler = sna->BlockHandler;
+
+ (*screen->BlockHandler) (i, data, timeout, read_mask);
+
+ sna->BlockHandler = screen->BlockHandler;
+ screen->BlockHandler = sna_block_handler;
+
+ sna_accel_block_handler(sna);
+}
+
+static void
+sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
+{
+ ScreenPtr screen = screenInfo.screens[i];
+ ScrnInfoPtr scrn = xf86Screens[i];
+ struct sna *sna = to_sna(scrn);
+
+ screen->WakeupHandler = sna->WakeupHandler;
+
+ (*screen->WakeupHandler) (i, data, result, read_mask);
+
+ sna->WakeupHandler = screen->WakeupHandler;
+ screen->WakeupHandler = sna_wakeup_handler;
+
+ sna_accel_wakeup_handler(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;
+
+ dev = udev_monitor_receive_device(sna->uevent_monitor);
+ if (!dev)
+ return;
+
+ udev_devnum = udev_device_get_devnum(dev);
+ fstat(sna->kgem.fd, &s);
+ /*
+ * 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)
+ RRGetInfo(screenInfo.screens[scrn->scrnIndex], TRUE);
+
+ 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 (!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;
+}
+
+static void
+sna_uevent_fini(ScrnInfoPtr scrn)
+{
+ struct sna *sna = to_sna(scrn);
+
+ if (sna->uevent_handler) {
+ struct udev *u = udev_monitor_get_udev(sna->uevent_monitor);
+
+ xf86RemoveGeneralHandler(sna->uevent_handler);
+
+ udev_monitor_unref(sna->uevent_monitor);
+ udev_unref(u);
+ sna->uevent_handler = NULL;
+ sna->uevent_monitor = NULL;
+ }
+}
+#endif /* HAVE_UDEV */
+
+static void sna_leave_vt(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct sna *sna = to_sna(scrn);
+ int ret;
+
+ xf86RotateFreeShadow(scrn);
+
+ xf86_hide_cursors(scrn);
+
+ ret = drmDropMaster(sna->kgem.fd);
+ if (ret)
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmDropMaster failed: %s\n", strerror(errno));
+}
+
+
+static Bool sna_close_screen(int scrnIndex, ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct sna *sna = to_sna(scrn);
+
+#if HAVE_UDEV
+ sna_uevent_fini(scrn);
+#endif
+
+ if (scrn->vtSema == TRUE)
+ sna_leave_vt(scrnIndex, 0);
+
+ sna_accel_close(sna);
+
+ xf86_cursors_fini(screen);
+
+ screen->CloseScreen = sna->CloseScreen;
+ (*screen->CloseScreen) (scrnIndex, screen);
+
+ if (sna->directRenderingOpen) {
+ sna_dri2_close(sna, screen);
+ sna->directRenderingOpen = FALSE;
+ }
+
+ xf86GARTCloseScreen(scrnIndex);
+
+ scrn->vtSema = FALSE;
+ return TRUE;
+}
+
+static Bool
+sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct sna *sna = to_sna(scrn);
+ VisualPtr visual;
+ struct pci_device *const device = sna->PciInfo;
+
+ scrn->videoRam = device->regions[2].size / 1024;
+
+#ifdef DRI2
+ sna->directRenderingOpen = sna_dri2_open(sna, screen);
+ if (sna->directRenderingOpen)
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: DRI2 Enabled\n");
+#endif
+
+ miClearVisualTypes();
+ if (!miSetVisualTypes(scrn->depth,
+ miGetDefaultVisualMask(scrn->depth),
+ scrn->rgbBits, scrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths())
+ return FALSE;
+
+ if (!fbScreenInit(screen, NULL,
+ scrn->virtualX, scrn->virtualY,
+ scrn->xDpi, scrn->yDpi,
+ scrn->displayWidth, scrn->bitsPerPixel))
+ return FALSE;
+
+ if (scrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ 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;
+ }
+ }
+ }
+
+ fbPictureInit(screen, NULL, 0);
+
+ xf86SetBlackWhitePixels(screen);
+
+ if (!sna_accel_init(screen, sna)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Hardware acceleration initialization failed\n");
+ return FALSE;
+ }
+
+ miInitializeBackingStore(screen);
+ xf86SetBackingStore(screen);
+ xf86SetSilkenMouse(screen);
+ miDCInitialize(screen, xf86GetPointerScreenFuncs());
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Initializing HW Cursor\n");
+ if (!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_ERROR,
+ "Hardware cursor initialization failed\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;
+ sna->CloseScreen = screen->CloseScreen;
+ screen->CloseScreen = sna_close_screen;
+ screen->CreateScreenResources = sna_create_screen_resources;
+
+ if (!xf86CrtcScreenInit(screen))
+ return FALSE;
+
+ 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 (serverGeneration == 1)
+ xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
+
+ sna_mode_init(sna);
+
+ sna->suspended = FALSE;
+
+#if HAVE_UDEV
+ sna_uevent_init(scrn);
+#endif
+
+ return TRUE;
+}
+
+static void sna_adjust_frame(int scrnIndex, int x, int y, int flags)
+{
+}
+
+static void sna_free_screen(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct sna *sna = to_sna(scrn);
+
+ if (sna) {
+ sna_mode_fini(sna);
+ sna_close_drm_master(sna);
+
+ free(sna);
+ scrn->driverPrivate = NULL;
+ }
+
+ if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
+ vgaHWFreeHWRec(xf86Screens[scrnIndex]);
+}
+
+/*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+static Bool sna_enter_vt(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct sna *sna = to_sna(scrn);
+
+ if (drmSetMaster(sna->kgem.fd)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: %s\n",
+ strerror(errno));
+ }
+
+ return xf86SetDesiredModes(scrn);
+}
+
+static Bool sna_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ return xf86SetSingleMode(xf86Screens[scrnIndex], mode, RR_Rotate_0);
+}
+
+static ModeStatus
+sna_valid_mode(int scrnIndex, 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(int scrnIndex, pmEvent event, Bool undo)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct sna *sna = to_sna(scrn);
+
+ 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(scrnIndex, 0);
+ sna->suspended = TRUE;
+ sleep(SUSPEND_SLEEP);
+ } else if (undo && sna->suspended) {
+ sleep(RESUME_SLEEP);
+ scrn->EnterVT(scrnIndex, 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(scrnIndex, 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;
+}
+
+void sna_init_scrn(ScrnInfoPtr scrn)
+{
+ scrn->PreInit = sna_pre_init;
+ scrn->ScreenInit = sna_screen_init;
+ scrn->SwitchMode = sna_switch_mode;
+ scrn->AdjustFrame = sna_adjust_frame;
+ scrn->EnterVT = sna_enter_vt;
+ scrn->LeaveVT = sna_leave_vt;
+ scrn->FreeScreen = sna_free_screen;
+ scrn->ValidMode = sna_valid_mode;
+ scrn->PMEvent = sna_pm_event;
+}