diff options
Diffstat (limited to 'src/sna/sna_driver.c')
-rw-r--r-- | src/sna/sna_driver.c | 925 |
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; +} |