summaryrefslogtreecommitdiff
path: root/src/intel_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/intel_driver.c')
-rw-r--r--src/intel_driver.c1265
1 files changed, 1265 insertions, 0 deletions
diff --git a/src/intel_driver.c b/src/intel_driver.c
new file mode 100644
index 00000000..4dbe2873
--- /dev/null
+++ b/src/intel_driver.c
@@ -0,0 +1,1265 @@
+/**************************************************************************
+
+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
+
+#ifndef PRINT_MODE_INFO
+#define PRINT_MODE_INFO 0
+#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 "shadow.h"
+#include "intel.h"
+#include "intel_video.h"
+#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
+#include <sys/mman.h>
+#endif
+
+#ifdef INTEL_XVMC
+#define _INTEL_XVMC_SERVER_
+#include "intel_hwmc.h"
+#endif
+
+#include "legacy/legacy.h"
+
+#include <sys/ioctl.h>
+#include "i915_drm.h"
+#include <xf86drmMode.h>
+
+#define BIT(x) (1 << (x))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define NB_OF(x) (sizeof (x) / sizeof (*x))
+
+/* *INDENT-OFF* */
+/*
+ * Note: "ColorKey" is provided for compatibility with the i810 driver.
+ * However, the correct option name is "VideoKey". "ColorKey" usually
+ * refers to the tranparency key for 8+24 overlays, not for video overlays.
+ */
+
+typedef enum {
+ OPTION_ACCELMETHOD,
+ OPTION_DRI,
+ OPTION_VIDEO_KEY,
+ OPTION_COLOR_KEY,
+ OPTION_FALLBACKDEBUG,
+ OPTION_TILING,
+ OPTION_SWAPBUFFERS_WAIT,
+#ifdef INTEL_XVMC
+ OPTION_XVMC,
+#endif
+ OPTION_PREFER_OVERLAY,
+ OPTION_DEBUG_FLUSH_BATCHES,
+ OPTION_DEBUG_FLUSH_CACHES,
+ OPTION_DEBUG_WAIT,
+} I830Opts;
+
+static OptionInfoRec I830Options[] = {
+ {OPTION_ACCELMETHOD, "AccelMethod", OPTV_ANYSTR, {0}, FALSE},
+ {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
+ {OPTION_FALLBACKDEBUG, "FallbackDebug", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_TILING, "Tiling", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
+#ifdef INTEL_XVMC
+ {OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, TRUE},
+#endif
+ {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_FLUSH_BATCHES, "DebugFlushBatches", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_FLUSH_CACHES, "DebugFlushCaches", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_WAIT, "DebugWait", OPTV_BOOLEAN, {0}, FALSE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+/* *INDENT-ON* */
+
+static void i830AdjustFrame(int scrnIndex, int x, int y, int flags);
+static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen);
+static Bool I830EnterVT(int scrnIndex, int flags);
+
+/* temporary */
+extern void xf86SetCursor(ScreenPtr screen, CursorPtr pCurs, int x, int y);
+
+#ifdef I830DEBUG
+void
+I830DPRINTF(const char *filename, int line, const char *function,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ ErrorF("\n##############################################\n"
+ "*** In function %s, on line %d, in file %s ***\n",
+ function, line, filename);
+ va_start(ap, fmt);
+ VErrorF(fmt, ap);
+ va_end(ap);
+ ErrorF("##############################################\n\n");
+}
+#endif /* #ifdef I830DEBUG */
+
+/* Export I830 options to i830 driver where necessary */
+const OptionInfoRec *intel_uxa_available_options(int chipid, int busid)
+{
+ return I830Options;
+}
+
+static Bool I830GetRec(ScrnInfoPtr scrn)
+{
+ if (scrn->driverPrivate)
+ return TRUE;
+ scrn->driverPrivate = xnfcalloc(sizeof(intel_screen_private), 1);
+
+ return TRUE;
+}
+
+static void I830FreeRec(ScrnInfoPtr scrn)
+{
+ if (!scrn)
+ return;
+ if (!scrn->driverPrivate)
+ return;
+
+ free(scrn->driverPrivate);
+ scrn->driverPrivate = NULL;
+}
+
+static void
+I830LoadPalette(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];
+
+ DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors);
+
+ for (p = 0; p < xf86_config->num_crtc; p++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[p];
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ /* Initialize to the old lookup table values. */
+ for (i = 0; i < 256; i++) {
+ lut_r[i] = intel_crtc->lut_r[i] << 8;
+ lut_g[i] = intel_crtc->lut_g[i] << 8;
+ lut_b[i] = intel_crtc->lut_b[i] << 8;
+ }
+
+ 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 i830CreateScreenResources(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ screen->CreateScreenResources = intel->CreateScreenResources;
+ if (!(*screen->CreateScreenResources) (screen))
+ return FALSE;
+
+ intel_uxa_create_screen_resources(screen);
+
+ return TRUE;
+}
+
+static void PreInitCleanup(ScrnInfoPtr scrn)
+{
+ I830FreeRec(scrn);
+}
+
+/*
+ * DRM mode setting Linux only at this point... later on we could
+ * add a wrapper here.
+ */
+static Bool intel_kernel_mode_enabled(ScrnInfoPtr scrn)
+{
+ struct pci_device *PciInfo;
+ EntityInfoPtr pEnt;
+ char *busIdString;
+ int ret;
+
+ pEnt = xf86GetEntityInfo(scrn->entityList[0]);
+ PciInfo = xf86GetPciInfoForEntity(pEnt->index);
+
+ if (!xf86LoaderCheckSymbol("DRICreatePCIBusID"))
+ return FALSE;
+
+ busIdString = DRICreatePCIBusID(PciInfo);
+
+ ret = drmCheckModesettingSupported(busIdString);
+ if (ret) {
+ if (xf86LoadKernelModule("i915"))
+ ret = drmCheckModesettingSupported(busIdString);
+ }
+ /* Be nice to the user and load fbcon too */
+ if (!ret)
+ (void)xf86LoadKernelModule("fbcon");
+ free(busIdString);
+ if (ret)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void intel_check_chipset_option(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ MessageType from = X_PROBED;
+
+ intel_detect_chipset(scrn,
+ intel->PciInfo,
+ &intel->chipset);
+
+ /* Set the Chipset and ChipRev, allowing config file entries to override. */
+ if (intel->pEnt->device->chipset && *intel->pEnt->device->chipset) {
+ scrn->chipset = intel->pEnt->device->chipset;
+ from = X_CONFIG;
+ } else if (intel->pEnt->device->chipID >= 0) {
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ intel->pEnt->device->chipID);
+ from = X_CONFIG;
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "ChipID override: 0x%04X\n",
+ intel->pEnt->device->chipID);
+ DEVICE_ID(intel->PciInfo) = intel->pEnt->device->chipID;
+ } else {
+ from = X_PROBED;
+ scrn->chipset = (char *)xf86TokenToString(intel_chipsets,
+ DEVICE_ID(intel->PciInfo));
+ }
+
+ if (intel->pEnt->device->chipRev >= 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ intel->pEnt->device->chipRev);
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, from, "Chipset: \"%s\"\n",
+ (scrn->chipset != NULL) ? scrn->chipset : "Unknown i8xx");
+}
+
+static Bool I830GetEarlyOptions(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* Process the options */
+ xf86CollectOptions(scrn, NULL);
+ if (!(intel->Options = malloc(sizeof(I830Options))))
+ return FALSE;
+ memcpy(intel->Options, I830Options, sizeof(I830Options));
+ xf86ProcessOptions(scrn->scrnIndex, scrn->options, intel->Options);
+
+ intel->fallback_debug = xf86ReturnOptValBool(intel->Options,
+ OPTION_FALLBACKDEBUG,
+ FALSE);
+
+ intel->debug_flush = 0;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_FLUSH_BATCHES,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_BATCHES;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_FLUSH_CACHES,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_CACHES;
+
+ if (xf86ReturnOptValBool(intel->Options,
+ OPTION_DEBUG_WAIT,
+ FALSE))
+ intel->debug_flush |= DEBUG_FLUSH_WAIT;
+
+ return TRUE;
+}
+
+static void intel_check_dri_option(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ intel->directRenderingType = DRI_NONE;
+ if (!xf86ReturnOptValBool(intel->Options, OPTION_DRI, TRUE))
+ intel->directRenderingType = DRI_DISABLED;
+
+ if (scrn->depth != 16 && scrn->depth != 24) {
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
+ "DRI is disabled because it "
+ "runs only at depths 16 and 24.\n");
+ intel->directRenderingType = DRI_DISABLED;
+ }
+}
+
+static Bool intel_open_drm_master(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct pci_device *dev = intel->PciInfo;
+ char *busid;
+ drmSetVersion sv;
+ struct drm_i915_getparam gp;
+ int err, has_gem;
+
+ /* We wish we had asprintf, but all we get is XNFprintf. */
+ busid = XNFprintf("pci:%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+
+ intel->drmSubFD = drmOpen("i915", busid);
+ if (intel->drmSubFD == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] Failed to open DRM device for %s: %s\n",
+ busid, strerror(errno));
+ free(busid);
+ return FALSE;
+ }
+
+ free(busid);
+
+ /* 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(intel->drmSubFD, &sv);
+ if (err != 0) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] failed to set drm interface version.\n");
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ return FALSE;
+ }
+
+ has_gem = FALSE;
+ gp.param = I915_PARAM_HAS_GEM;
+ gp.value = &has_gem;
+ (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM,
+ &gp, sizeof(gp));
+ if (!has_gem) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "[drm] Failed to detect GEM. Kernel 2.6.28 required.\n");
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void intel_close_drm_master(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ if (intel && intel->drmSubFD > 0) {
+ drmClose(intel->drmSubFD);
+ intel->drmSubFD = -1;
+ }
+}
+
+static void intel_init_bufmgr(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int batch_size;
+
+ if (intel->bufmgr)
+ return;
+
+ batch_size = 4096 * 4;
+
+ /* The 865 has issues with larger-than-page-sized batch buffers. */
+ if (IS_I865G(intel))
+ batch_size = 4096;
+
+ intel->bufmgr = drm_intel_bufmgr_gem_init(intel->drmSubFD, batch_size);
+ drm_intel_bufmgr_gem_enable_reuse(intel->bufmgr);
+ drm_intel_bufmgr_gem_enable_fenced_relocs(intel->bufmgr);
+
+ list_init(&intel->batch_pixmaps);
+ list_init(&intel->flush_pixmaps);
+ list_init(&intel->in_flight);
+}
+
+static Bool I830DrmModeInit(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ intel_init_bufmgr(scrn);
+
+ if (drmmode_pre_init(scrn, intel->drmSubFD, intel->cpp) == FALSE) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Kernel modesetting setup failed\n");
+ PreInitCleanup(scrn);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void I830XvInit(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ MessageType from = X_PROBED;
+
+ intel->XvPreferOverlay =
+ xf86ReturnOptValBool(intel->Options, OPTION_PREFER_OVERLAY, FALSE);
+
+ if (xf86GetOptValInteger(intel->Options, OPTION_VIDEO_KEY,
+ &(intel->colorKey))) {
+ from = X_CONFIG;
+ } else if (xf86GetOptValInteger(intel->Options, OPTION_COLOR_KEY,
+ &(intel->colorKey))) {
+ from = X_CONFIG;
+ } else {
+ intel->colorKey =
+ (1 << scrn->offset.red) | (1 << scrn->offset.green) |
+ (((scrn->mask.blue >> scrn->offset.blue) - 1) <<
+ scrn->offset.blue);
+ from = X_DEFAULT;
+ }
+ xf86DrvMsg(scrn->scrnIndex, from, "video overlay key set to 0x%x\n",
+ intel->colorKey);
+}
+
+/**
+ * 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 I830PreInit(ScrnInfoPtr scrn, int flags)
+{
+ intel_screen_private *intel;
+ rgb defaultWeight = { 0, 0, 0 };
+ EntityInfoPtr pEnt;
+ int flags24;
+ Gamma zeros = { 0.0, 0.0, 0.0 };
+ int drm_mode_setting;
+
+ if (scrn->numEntities != 1)
+ return FALSE;
+
+ drm_mode_setting = intel_kernel_mode_enabled(scrn);
+ if (!drm_mode_setting) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "No kernel modesetting driver detected.\n");
+ return FALSE;
+ }
+
+ pEnt = xf86GetEntityInfo(scrn->entityList[0]);
+
+ if (flags & PROBE_DETECT)
+ return TRUE;
+
+ /* Allocate driverPrivate */
+ if (!I830GetRec(scrn))
+ return FALSE;
+
+ intel = intel_get_screen_private(scrn);
+ intel->pEnt = pEnt;
+
+ scrn->displayWidth = 640; /* default it */
+
+ if (intel->pEnt->location.type != BUS_PCI)
+ return FALSE;
+
+ intel->PciInfo = xf86GetPciInfoForEntity(intel->pEnt->index);
+
+ if (!intel_open_drm_master(scrn))
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to become DRM master.\n");
+
+ 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 I830 driver\n",
+ scrn->depth);
+ return FALSE;
+ }
+ xf86PrintDepthBpp(scrn);
+
+ if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
+ return FALSE;
+ if (!xf86SetDefaultVisual(scrn, -1))
+ return FALSE;
+
+ intel->cpp = scrn->bitsPerPixel / 8;
+
+ if (!I830GetEarlyOptions(scrn))
+ return FALSE;
+
+ intel_check_chipset_option(scrn);
+ intel_check_dri_option(scrn);
+
+ I830XvInit(scrn);
+
+ if (!I830DrmModeInit(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. */
+ if (xf86ReturnOptValBool(intel->Options, OPTION_DRI, FALSE) &&
+ intel->directRenderingType != DRI_DISABLED) {
+ xf86LoadSubModule(scrn, "dri2");
+ }
+
+ return TRUE;
+}
+
+enum pipe {
+ PIPE_A = 0,
+ PIPE_B,
+};
+
+/**
+ * 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.
+ */
+void IntelEmitInvarientState(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ /* If we've emitted our state since the last clobber by another client,
+ * skip it.
+ */
+ if (intel->last_3d != LAST_3D_OTHER)
+ return;
+
+ if (!IS_I965G(intel)) {
+ if (IS_I9XX(intel))
+ I915EmitInvarientState(scrn);
+ else
+ I830EmitInvarientState(scrn);
+ }
+}
+
+static void
+I830BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
+{
+ ScreenPtr screen = screenInfo.screens[i];
+ ScrnInfoPtr scrn = xf86Screens[i];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ screen->BlockHandler = intel->BlockHandler;
+
+ (*screen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+
+ intel->BlockHandler = screen->BlockHandler;
+ screen->BlockHandler = I830BlockHandler;
+
+ if (scrn->vtSema) {
+ /* Emit a flush of the rendering cache, or on the 965 and beyond
+ * rendering results may not hit the framebuffer until significantly
+ * later.
+ */
+ intel_batch_submit(scrn,
+ intel->need_mi_flush ||
+ !list_is_empty(&intel->flush_pixmaps));
+ drmCommandNone(intel->drmSubFD, DRM_I915_GEM_THROTTLE);
+ }
+
+ intel_uxa_block_handler(intel);
+ intel_video_block_handler(intel);
+}
+
+static void intel_fixup_mtrrs(ScrnInfoPtr scrn)
+{
+#ifdef HAS_MTRR_SUPPORT
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int fd;
+ struct mtrr_gentry gentry;
+ struct mtrr_sentry sentry;
+
+ if ((fd = open("/proc/mtrr", O_RDONLY, 0)) != -1) {
+ for (gentry.regnum = 0;
+ ioctl(fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+ ++gentry.regnum) {
+
+ if (gentry.size < 1) {
+ /* DISABLED */
+ continue;
+ }
+
+ /* Check the MTRR range is one we like and if not - remove it.
+ * The Xserver common layer will then setup the right range
+ * for us.
+ */
+ if (gentry.base == intel->LinearAddr &&
+ gentry.size < intel->FbMapSize) {
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "Removing bad MTRR range (base 0x%lx, size 0x%x)\n",
+ gentry.base, gentry.size);
+
+ sentry.base = gentry.base;
+ sentry.size = gentry.size;
+ sentry.type = gentry.type;
+
+ if (ioctl(fd, MTRRIOC_DEL_ENTRY, &sentry) == -1) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to remove bad MTRR range\n");
+ }
+ }
+ }
+ close(fd);
+ }
+#endif
+}
+
+static Bool
+intel_init_initial_framebuffer(ScrnInfoPtr scrn)
+{
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ unsigned long pitch;
+
+ intel->front_buffer = intel_allocate_framebuffer(scrn,
+ scrn->virtualX,
+ scrn->virtualY,
+ intel->cpp,
+ &pitch);
+
+ if (!intel->front_buffer) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't allocate initial framebuffer.\n");
+ return FALSE;
+ }
+
+ scrn->displayWidth = pitch / intel->cpp;
+
+ return TRUE;
+}
+
+Bool intel_crtc_on(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int i, active_outputs = 0;
+
+ /* Kernel manages CRTC status based out output config */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ if (output->crtc == crtc &&
+ drmmode_output_dpms_status(output) == DPMSModeOn)
+ active_outputs++;
+ }
+
+ if (active_outputs)
+ return TRUE;
+ return FALSE;
+}
+
+int intel_crtc_to_pipe(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ return drmmode_get_pipe_from_crtc_id(intel->bufmgr, crtc);
+}
+
+static Bool
+I830ScreenInit(int scrnIndex, ScreenPtr screen, int argc, char **argv)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ VisualPtr visual;
+#ifdef INTEL_XVMC
+ MessageType from;
+#endif
+ struct pci_device *const device = intel->PciInfo;
+ int fb_bar = IS_I9XX(intel) ? 2 : 0;
+
+ /*
+ * The "VideoRam" config file parameter specifies the maximum amount of
+ * memory that will be used/allocated. When not present, we allow the
+ * driver to allocate as much memory as it wishes to satisfy its
+ * allocations, but if agpgart support isn't available, it gets limited
+ * to the amount of pre-allocated ("stolen") memory.
+ *
+ * Note that in using this value for allocator initialization, we're
+ * limiting aperture allocation to the VideoRam option, rather than limiting
+ * actual memory allocation, so alignment and things will cause less than
+ * VideoRam to be actually used.
+ */
+ scrn->videoRam = intel->FbMapSize / KB(1);
+ if (intel->pEnt->device->videoRam != 0) {
+ if (scrn->videoRam != intel->pEnt->device->videoRam) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "VideoRam configuration found, which is no "
+ "longer used.\n");
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "Continuing with (ignored) %dkB VideoRam "
+ "instead of %d kB.\n",
+ scrn->videoRam,
+ intel->pEnt->device->videoRam);
+ }
+ }
+
+ scrn->videoRam = device->regions[fb_bar].size / 1024;
+
+#ifdef DRI2
+ if (intel->directRenderingType == DRI_NONE
+ && I830DRI2ScreenInit(screen))
+ intel->directRenderingType = DRI_DRI2;
+#endif
+
+ /* Enable tiling by default */
+ intel->tiling = TRUE;
+
+ /* Allow user override if they set a value */
+ if (xf86IsOptionSet(intel->Options, OPTION_TILING)) {
+ if (xf86ReturnOptValBool(intel->Options, OPTION_TILING, FALSE))
+ intel->tiling = TRUE;
+ else
+ intel->tiling = FALSE;
+ }
+
+ /* SwapBuffers delays to avoid tearing */
+ intel->swapbuffers_wait = TRUE;
+
+ /* Allow user override if they set a value */
+ if (xf86IsOptionSet(intel->Options, OPTION_SWAPBUFFERS_WAIT)) {
+ if (xf86ReturnOptValBool
+ (intel->Options, OPTION_SWAPBUFFERS_WAIT, FALSE))
+ intel->swapbuffers_wait = TRUE;
+ else
+ intel->swapbuffers_wait = FALSE;
+ }
+
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Tiling %sabled\n",
+ intel->tiling ? "en" : "dis");
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n",
+ intel->swapbuffers_wait ? "en" : "dis");
+
+ intel->last_3d = LAST_3D_OTHER;
+ intel->overlayOn = FALSE;
+
+ /*
+ * Set this so that the overlay allocation is factored in when
+ * appropriate.
+ */
+ intel->XvEnabled = TRUE;
+
+ xf86DrvMsg(scrn->scrnIndex,
+ intel->pEnt->device->videoRam ? X_CONFIG : X_DEFAULT,
+ "VideoRam: %d KB\n", scrn->videoRam);
+
+ if (!intel_init_initial_framebuffer(scrn))
+ return FALSE;
+
+ intel_fixup_mtrrs(scrn);
+
+ intel_batch_init(scrn);
+
+ if (IS_I965G(intel))
+ gen4_render_state_init(scrn);
+
+ miClearVisualTypes();
+ if (!miSetVisualTypes(scrn->depth,
+ miGetDefaultVisualMask(scrn->depth),
+ scrn->rgbBits, scrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths())
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n");
+
+ DPRINTF(PFX, "assert( if(!fbScreenInit(screen, ...) )\n");
+ 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 (!intel_uxa_init(screen)) {
+ 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, I810_CURSOR_X, I810_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;
+
+ if (!I830EnterVT(scrnIndex, 0))
+ return FALSE;
+
+ intel->BlockHandler = screen->BlockHandler;
+ screen->BlockHandler = I830BlockHandler;
+
+ screen->SaveScreen = xf86SaveScreen;
+ intel->CloseScreen = screen->CloseScreen;
+ screen->CloseScreen = I830CloseScreen;
+ intel->CreateScreenResources = screen->CreateScreenResources;
+ screen->CreateScreenResources = i830CreateScreenResources;
+
+ if (!xf86CrtcScreenInit(screen))
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!miCreateDefColormap(screen)) )\n");
+ if (!miCreateDefColormap(screen))
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!xf86HandleColormaps(screen, ...)) )\n");
+ if (!xf86HandleColormaps(screen, 256, 8, I830LoadPalette, NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH |
+ CMAP_PALETTED_TRUECOLOR)) {
+ return FALSE;
+ }
+
+ xf86DPMSInit(screen, xf86DPMSSet, 0);
+
+#ifdef INTEL_XVMC
+ if (IS_I965G(intel))
+ intel->XvMCEnabled = TRUE;
+ from = ((intel->directRenderingType == DRI_DRI2) &&
+ xf86GetOptValBool(intel->Options, OPTION_XVMC,
+ &intel->XvMCEnabled) ? X_CONFIG : X_DEFAULT);
+ xf86DrvMsg(scrn->scrnIndex, from, "Intel XvMC decoder %sabled\n",
+ intel->XvMCEnabled ? "en" : "dis");
+#endif
+ /* Init video */
+ if (intel->XvEnabled)
+ I830InitVideo(screen);
+
+#if defined(DRI2)
+ switch (intel->directRenderingType) {
+ case DRI_DRI2:
+ intel->directRenderingOpen = TRUE;
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: DRI2 Enabled\n");
+ break;
+ case DRI_DISABLED:
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Disabled\n");
+ break;
+ case DRI_NONE:
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Failed\n");
+ break;
+ }
+#else
+ xf86DrvMsg(scrn->scrnIndex, X_INFO,
+ "direct rendering: Not available\n");
+#endif
+
+ if (serverGeneration == 1)
+ xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
+
+ intel->suspended = FALSE;
+
+ return uxa_resources_init(screen);
+}
+
+static void i830AdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+}
+
+static void I830FreeScreen(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+
+ intel_close_drm_master(scrn);
+
+ I830FreeRec(xf86Screens[scrnIndex]);
+ if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
+ vgaHWFreeHWRec(xf86Screens[scrnIndex]);
+}
+
+static void I830LeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int ret;
+
+ DPRINTF(PFX, "Leave VT\n");
+
+ xf86RotateFreeShadow(scrn);
+
+ xf86_hide_cursors(scrn);
+
+ ret = drmDropMaster(intel->drmSubFD);
+ if (ret)
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmDropMaster failed: %s\n", strerror(errno));
+}
+
+/*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+static Bool I830EnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int ret;
+
+ DPRINTF(PFX, "Enter VT\n");
+
+ ret = drmSetMaster(intel->drmSubFD);
+ if (ret) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: %s\n",
+ strerror(errno));
+ }
+
+ intel_set_gem_max_sizes(scrn);
+
+ if (!xf86SetDesiredModes(scrn))
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool I830SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+
+ return xf86SetSingleMode(scrn, mode, RR_Rotate_0);
+}
+
+static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (scrn->vtSema == TRUE) {
+ I830LeaveVT(scrnIndex, 0);
+ }
+
+ if (intel->uxa_driver) {
+ uxa_driver_fini(screen);
+ free(intel->uxa_driver);
+ intel->uxa_driver = NULL;
+ }
+ if (intel->front_buffer) {
+ intel_set_pixmap_bo(screen->GetScreenPixmap(screen), NULL);
+ drmmode_closefb(scrn);
+ drm_intel_bo_unreference(intel->front_buffer);
+ intel->front_buffer = NULL;
+ }
+
+ intel_batch_teardown(scrn);
+
+ if (IS_I965G(intel))
+ gen4_render_state_cleanup(scrn);
+
+ xf86_cursors_fini(screen);
+
+ drm_intel_bo_unreference(intel->front_buffer);
+ intel->front_buffer = NULL;
+
+ i965_free_video(scrn);
+
+ screen->CloseScreen = intel->CloseScreen;
+ (*screen->CloseScreen) (scrnIndex, screen);
+
+ if (intel->directRenderingOpen
+ && intel->directRenderingType == DRI_DRI2) {
+ intel->directRenderingOpen = FALSE;
+ I830DRI2CloseScreen(screen);
+ }
+
+ xf86GARTCloseScreen(scrnIndex);
+
+ scrn->vtSema = FALSE;
+ return TRUE;
+}
+
+static ModeStatus
+I830ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+{
+ if (mode->Flags & V_INTERLACE) {
+ if (verbose) {
+ xf86DrvMsg(scrnIndex, X_PROBED,
+ "Removing interlaced mode \"%s\"\n",
+ mode->name);
+ }
+ return MODE_BAD;
+ }
+ 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 I830PMEvent(int scrnIndex, pmEvent event, Bool undo)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ DPRINTF(PFX, "Enter VT, event %d, undo: %s\n", event,
+ BOOLTOSTRING(undo));
+
+ 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 && !intel->suspended) {
+ scrn->LeaveVT(scrnIndex, 0);
+ intel->suspended = TRUE;
+ sleep(SUSPEND_SLEEP);
+ } else if (undo && intel->suspended) {
+ sleep(RESUME_SLEEP);
+ scrn->EnterVT(scrnIndex, 0);
+ intel->suspended = FALSE;
+ }
+ break;
+ case XF86_APM_STANDBY_RESUME:
+ case XF86_APM_NORMAL_RESUME:
+ case XF86_APM_CRITICAL_RESUME:
+ if (intel->suspended) {
+ sleep(RESUME_SLEEP);
+ scrn->EnterVT(scrnIndex, 0);
+ intel->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:
+ ErrorF("I830PMEvent: Capability change\n");
+
+ SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
+
+ break;
+ default:
+ ErrorF("I830PMEvent: received APM event %d\n", event);
+ }
+ return TRUE;
+}
+
+xf86CrtcPtr intel_pipe_to_crtc(ScrnInfoPtr scrn, int pipe)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c;
+
+ for (c = 0; c < config->num_crtc; c++) {
+ xf86CrtcPtr crtc = config->crtc[c];
+ I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+
+ if (intel_crtc->pipe == pipe)
+ return crtc;
+ }
+
+ return NULL;
+}
+
+void intel_init_scrn(ScrnInfoPtr scrn)
+{
+ scrn->PreInit = I830PreInit;
+ scrn->ScreenInit = I830ScreenInit;
+ scrn->SwitchMode = I830SwitchMode;
+ scrn->AdjustFrame = i830AdjustFrame;
+ scrn->EnterVT = I830EnterVT;
+ scrn->LeaveVT = I830LeaveVT;
+ scrn->FreeScreen = I830FreeScreen;
+ scrn->ValidMode = I830ValidMode;
+ scrn->PMEvent = I830PMEvent;
+}