From db7cd7b9f0ce8e435c121071eaadf8e6dcebf9e8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 1 Aug 2010 11:25:42 +0100 Subject: [PATCH] Rename drmmode_display to intel_display And fixup all the drmmode_* functions to have an intel prefix and categorise those into intel_mode, intel_crtc, intel_output and intel_property so that the functions are a little more self-descriptive and, more importantly, are consistent. Signed-off-by: Chris Wilson --- src/Makefile.am | 6 +- src/drmmode_display.c | 1565 ---------------------------------------- src/intel.h | 22 +- src/intel_display.c | 1582 +++++++++++++++++++++++++++++++++++++++++ src/intel_driver.c | 16 +- src/intel_video.c | 2 +- 6 files changed, 1604 insertions(+), 1589 deletions(-) delete mode 100644 src/drmmode_display.c create mode 100644 src/intel_display.c diff --git a/src/Makefile.am b/src/Makefile.am index fbccf0bd..b0a1cf79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,10 +43,11 @@ intel_drv_la_SOURCES = \ common.h \ intel.h \ intel_module.c \ - intel_driver.c \ - intel_driver.h \ intel_batchbuffer.c \ intel_batchbuffer.h \ + intel_display.c \ + intel_driver.c \ + intel_driver.h \ intel_memory.c \ intel_uxa.c \ intel_video.c \ @@ -62,7 +63,6 @@ intel_drv_la_SOURCES = \ i965_reg.h \ i965_video.c \ i965_render.c \ - drmmode_display.c \ $(NULL) if DRI diff --git a/src/drmmode_display.c b/src/drmmode_display.c deleted file mode 100644 index fd433221..00000000 --- a/src/drmmode_display.c +++ /dev/null @@ -1,1565 +0,0 @@ -/* - * Copyright © 2007 Red Hat, Inc. - * - * 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 - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * 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 NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS 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: - * Dave Airlie - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include - -#include "xorgVersion.h" - -#include "intel.h" -#include "intel_bufmgr.h" -#include "xf86drmMode.h" -#include "X11/Xatom.h" - -typedef struct { - int fd; - uint32_t fb_id; - drmModeResPtr mode_res; - int cpp; - - drmEventContext event_context; - void *event_data; - int old_fb_id; - int flip_count; - - struct list outputs; - struct list crtcs; -} drmmode_rec, *drmmode_ptr; - -typedef struct { - drmmode_ptr drmmode; - drmModeModeInfo kmode; - drmModeCrtcPtr mode_crtc; - dri_bo *cursor; - dri_bo *rotate_bo; - uint32_t rotate_pitch; - uint32_t rotate_fb_id; - xf86CrtcPtr crtc; - struct list link; -} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; - -typedef struct { - drmModePropertyPtr mode_prop; - uint64_t value; - int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ - Atom *atoms; -} drmmode_prop_rec, *drmmode_prop_ptr; - -struct fixed_panel_lvds { - int hdisplay; - int vdisplay; -}; -typedef struct { - drmmode_ptr drmmode; - int output_id; - drmModeConnectorPtr mode_output; - drmModeEncoderPtr mode_encoder; - drmModePropertyBlobPtr edid_blob; - int num_props; - drmmode_prop_ptr props; - void *private_data; - int dpms_mode; - const char *backlight_iface; - int backlight_active_level; - int backlight_max; - xf86OutputPtr output; - struct list link; -} drmmode_output_private_rec, *drmmode_output_private_ptr; - -static void -drmmode_output_dpms(xf86OutputPtr output, int mode); - -#define BACKLIGHT_CLASS "/sys/class/backlight" - -/* - * List of available kernel interfaces in priority order - */ -static const char *backlight_interfaces[] = { - "asus-laptop", - "eeepc", - "thinkpad_screen", - "mbp_backlight", - "acpi_video1", - "acpi_video0", - "fujitsu-laptop", - "sony", - "samsung", - NULL, -}; -/* - * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table + - * '/' + "max_backlight" - */ -#define BACKLIGHT_PATH_LEN 80 -/* Enough for 10 digits of backlight + '\n' + '\0' */ -#define BACKLIGHT_VALUE_LEN 12 - -static inline int -crtc_id(drmmode_crtc_private_ptr drmmode_crtc) -{ - return drmmode_crtc->mode_crtc->crtc_id; -} - -static void -drmmode_backlight_set(xf86OutputPtr output, int level) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; - int fd, len, ret; - - if (level > drmmode_output->backlight_max) - level = drmmode_output->backlight_max; - if (! drmmode_output->backlight_iface || level < 0) - return; - - len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); - sprintf(path, "%s/%s/brightness", - BACKLIGHT_CLASS, drmmode_output->backlight_iface); - fd = open(path, O_RDWR); - if (fd == -1) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight " - "control: %s\n", path, strerror(errno)); - return; - } - - ret = write(fd, val, len); - if (ret == -1) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight " - "control failed: %s\n", path, strerror(errno)); - } - - close(fd); -} - -static int -drmmode_backlight_get(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; - int fd, level; - - if (! drmmode_output->backlight_iface) - return -1; - - sprintf(path, "%s/%s/actual_brightness", - BACKLIGHT_CLASS, drmmode_output->backlight_iface); - fd = open(path, O_RDONLY); - if (fd == -1) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " - "for backlight control: %s\n", path, strerror(errno)); - return -1; - } - - memset(val, 0, sizeof(val)); - if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { - close(fd); - return -1; - } - - close(fd); - - level = atoi(val); - if (level > drmmode_output->backlight_max) - level = drmmode_output->backlight_max; - if (level < 0) - level = -1; - return level; -} - -static int -drmmode_backlight_get_max(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; - int fd, max = 0; - - sprintf(path, "%s/%s/max_brightness", - BACKLIGHT_CLASS, drmmode_output->backlight_iface); - fd = open(path, O_RDONLY); - if (fd == -1) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " - "for backlight control: %s\n", path, strerror(errno)); - return 0; - } - - memset(val, 0, sizeof(val)); - if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { - close(fd); - return -1; - } - - close(fd); - - max = atoi(val); - if (max <= 0) - max = -1; - return max; -} - -static void -drmmode_backlight_init(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - char path[BACKLIGHT_PATH_LEN]; - struct stat buf; - int i; - - for (i = 0; backlight_interfaces[i] != NULL; i++) { - sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]); - if (!stat(path, &buf)) { - drmmode_output->backlight_iface = backlight_interfaces[i]; - drmmode_output->backlight_max = drmmode_backlight_get_max(output); - drmmode_output->backlight_active_level = drmmode_backlight_get(output); - if (drmmode_backlight_get_max(output)) { - xf86DrvMsg(output->scrn->scrnIndex, X_INFO, - "found backlight control interface %s\n", path); - return; - } - } - } - drmmode_output->backlight_iface = NULL; -} - - -static void -drmmode_ConvertFromKMode(ScrnInfoPtr scrn, - drmModeModeInfoPtr kmode, - DisplayModePtr mode) -{ - memset(mode, 0, sizeof(DisplayModeRec)); - mode->status = MODE_OK; - - mode->Clock = kmode->clock; - - mode->HDisplay = kmode->hdisplay; - mode->HSyncStart = kmode->hsync_start; - mode->HSyncEnd = kmode->hsync_end; - mode->HTotal = kmode->htotal; - mode->HSkew = kmode->hskew; - - mode->VDisplay = kmode->vdisplay; - mode->VSyncStart = kmode->vsync_start; - mode->VSyncEnd = kmode->vsync_end; - mode->VTotal = kmode->vtotal; - mode->VScan = kmode->vscan; - - mode->Flags = kmode->flags; //& FLAG_BITS; - mode->name = strdup(kmode->name); - - if (kmode->type & DRM_MODE_TYPE_DRIVER) - mode->type = M_T_DRIVER; - if (kmode->type & DRM_MODE_TYPE_PREFERRED) - mode->type |= M_T_PREFERRED; - xf86SetModeCrtc (mode, scrn->adjustFlags); -} - -static void -drmmode_ConvertToKMode(ScrnInfoPtr scrn, - drmModeModeInfoPtr kmode, - DisplayModePtr mode) -{ - memset(kmode, 0, sizeof(*kmode)); - - kmode->clock = mode->Clock; - kmode->hdisplay = mode->HDisplay; - kmode->hsync_start = mode->HSyncStart; - kmode->hsync_end = mode->HSyncEnd; - kmode->htotal = mode->HTotal; - kmode->hskew = mode->HSkew; - - kmode->vdisplay = mode->VDisplay; - kmode->vsync_start = mode->VSyncStart; - kmode->vsync_end = mode->VSyncEnd; - kmode->vtotal = mode->VTotal; - kmode->vscan = mode->VScan; - - kmode->flags = mode->Flags; //& FLAG_BITS; - if (mode->name) - strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); - kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; - -} - -static void -drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode) -{ - -} - -static Bool -drmmode_apply(xf86CrtcPtr crtc) -{ - ScrnInfoPtr scrn = crtc->scrn; - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); - uint32_t *output_ids; - int output_count = 0; - int fb_id, x, y; - int i, ret; - - output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); - if (!output_ids) - return FALSE; - - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - drmmode_output_private_ptr drmmode_output; - - if (output->crtc != crtc) - continue; - - drmmode_output = output->driver_private; - output_ids[output_count] = - drmmode_output->mode_output->connector_id; - output_count++; - } - -#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) - if (!xf86CrtcRotate(crtc, mode, rotation)) - goto done; -#else - if (!xf86CrtcRotate(crtc)) - goto done; -#endif - -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) - crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, - crtc->gamma_blue, crtc->gamma_size); -#endif - - - x = crtc->x; - y = crtc->y; - fb_id = drmmode->fb_id; - if (drmmode_crtc->rotate_fb_id) { - fb_id = drmmode_crtc->rotate_fb_id; - x = 0; - y = 0; - } - ret = drmModeSetCrtc(drmmode->fd, crtc_id(drmmode_crtc), - fb_id, x, y, output_ids, output_count, - &drmmode_crtc->kmode); - if (ret) { - xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "failed to set mode: %s\n", strerror(-ret)); - ret = FALSE; - } else - ret = TRUE; - - /* Turn on any outputs on this crtc that may have been disabled */ - for (i = 0; i < xf86_config->num_output; i++) { - xf86OutputPtr output = xf86_config->output[i]; - - if (output->crtc != crtc) - continue; - - drmmode_output_dpms(output, DPMSModeOn); - } - - intel_set_gem_max_sizes(scrn); - - if (scrn->pScreen) - xf86_reload_cursors(scrn->pScreen); - - return ret; - -done: - free(output_ids); - return FALSE; -} - -static Bool -drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, - Rotation rotation, int x, int y) -{ - ScrnInfoPtr scrn = crtc->scrn; - intel_screen_private *intel = intel_get_screen_private(scrn); - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - int saved_x, saved_y; - Rotation saved_rotation; - DisplayModeRec saved_mode; - int ret = TRUE; - unsigned int pitch = scrn->displayWidth * intel->cpp; - - if (drmmode->fb_id == 0) { - ret = drmModeAddFB(drmmode->fd, - scrn->virtualX, scrn->virtualY, - scrn->depth, scrn->bitsPerPixel, - pitch, intel->front_buffer->handle, - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb\n"); - return FALSE; - } - } - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - saved_rotation = crtc->rotation; - - crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - crtc->rotation = rotation; - - drmmode_ConvertToKMode(crtc->scrn, &drmmode_crtc->kmode, mode); - ret = drmmode_apply(crtc); - if (!ret) { - crtc->x = saved_x; - crtc->y = saved_y; - crtc->rotation = saved_rotation; - crtc->mode = saved_mode; - } - return ret; -} - -static void -drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) -{ - -} - -static void -drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - - drmModeMoveCursor(drmmode->fd, crtc_id(drmmode_crtc), x, y); -} - -static void -drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - int ret; - - /* cursor should be mapped already */ - ret = dri_bo_subdata(drmmode_crtc->cursor, 0, 64*64*4, image); - if (ret) - xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "failed to set cursor: %s\n", strerror(-ret)); - - return; -} - - -static void -drmmode_hide_cursor (xf86CrtcPtr crtc) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - - drmModeSetCursor(drmmode->fd, crtc_id(drmmode_crtc), 0, 64, 64); -} - -static void -drmmode_show_cursor (xf86CrtcPtr crtc) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - - drmModeSetCursor(drmmode->fd, crtc_id(drmmode_crtc), - drmmode_crtc->cursor->handle, 64, 64); -} - -static void * -drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) -{ - ScrnInfoPtr scrn = crtc->scrn; - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - unsigned long rotate_pitch; - int ret; - - drmmode_crtc->rotate_bo = intel_allocate_framebuffer(scrn, - width, height, - drmmode->cpp, - &rotate_pitch); - - if (!drmmode_crtc->rotate_bo) { - xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow memory for rotated CRTC\n"); - return NULL; - } - - ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, - crtc->scrn->bitsPerPixel, rotate_pitch, - drmmode_crtc->rotate_bo->handle, - &drmmode_crtc->rotate_fb_id); - if (ret) { - ErrorF("failed to add rotate fb\n"); - drm_intel_bo_unreference(drmmode_crtc->rotate_bo); - return NULL; - } - - drmmode_crtc->rotate_pitch = rotate_pitch; - return drmmode_crtc->rotate_bo; -} - -static PixmapPtr -drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) -{ - ScrnInfoPtr scrn = crtc->scrn; - intel_screen_private *intel = intel_get_screen_private(scrn); - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - PixmapPtr rotate_pixmap; - - if (!data) { - data = drmmode_crtc_shadow_allocate (crtc, width, height); - if (!data) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow pixmap for rotated CRTC\n"); - return NULL; - } - } - if (drmmode_crtc->rotate_bo == NULL) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow pixmap for rotated CRTC\n"); - return NULL; - } - - rotate_pixmap = GetScratchPixmapHeader(scrn->pScreen, - width, height, - scrn->depth, - scrn->bitsPerPixel, - drmmode_crtc->rotate_pitch, - NULL); - - if (rotate_pixmap == NULL) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow pixmap for rotated CRTC\n"); - return NULL; - } - - intel_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo); - - intel->shadow_present = TRUE; - - return rotate_pixmap; -} - -static void -drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) -{ - ScrnInfoPtr scrn = crtc->scrn; - intel_screen_private *intel = intel_get_screen_private(scrn); - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - - if (rotate_pixmap) { - intel_set_pixmap_bo(rotate_pixmap, NULL); - FreeScratchPixmapHeader(rotate_pixmap); - } - - - if (data) { - /* Be sure to sync acceleration before the memory gets - * unbound. */ - drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); - drmmode_crtc->rotate_fb_id = 0; - dri_bo_unreference(drmmode_crtc->rotate_bo); - drmmode_crtc->rotate_bo = NULL; - } - intel->shadow_present = FALSE; -} - -static void -drmmode_crtc_gamma_set(xf86CrtcPtr crtc, - CARD16 *red, CARD16 *green, CARD16 *blue, int size) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - - drmModeCrtcSetGamma(drmmode->fd, crtc_id(drmmode_crtc), - size, red, green, blue); -} - -static void -drmmode_crtc_destroy(xf86CrtcPtr crtc) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - - drm_intel_bo_unreference(drmmode_crtc->cursor); - drmmode_crtc->cursor = NULL; - - list_del(&drmmode_crtc->link); - free(drmmode_crtc); - - crtc->driver_private = NULL; -} - -static const xf86CrtcFuncsRec drmmode_crtc_funcs = { - .dpms = drmmode_crtc_dpms, - .set_mode_major = drmmode_set_mode_major, - .set_cursor_colors = drmmode_set_cursor_colors, - .set_cursor_position = drmmode_set_cursor_position, - .show_cursor = drmmode_show_cursor, - .hide_cursor = drmmode_hide_cursor, - .load_cursor_argb = drmmode_load_cursor_argb, - .shadow_create = drmmode_crtc_shadow_create, - .shadow_allocate = drmmode_crtc_shadow_allocate, - .shadow_destroy = drmmode_crtc_shadow_destroy, - .gamma_set = drmmode_crtc_gamma_set, - .destroy = drmmode_crtc_destroy, -}; - - -static void -drmmode_crtc_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, int num) -{ - intel_screen_private *intel = intel_get_screen_private(scrn); - xf86CrtcPtr crtc; - drmmode_crtc_private_ptr drmmode_crtc; - - crtc = xf86CrtcCreate(scrn, &drmmode_crtc_funcs); - if (crtc == NULL) - return; - - drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); - drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, - drmmode->mode_res->crtcs[num]); - drmmode_crtc->drmmode = drmmode; - crtc->driver_private = drmmode_crtc; - - drmmode_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor", - HWCURSOR_SIZE_ARGB, - GTT_PAGE_SIZE); - drm_intel_bo_disable_reuse(drmmode_crtc->cursor); - - drmmode_crtc->crtc = crtc; - list_add(&drmmode_crtc->link, &drmmode->crtcs); -} - -static xf86OutputStatus -drmmode_output_detect(xf86OutputPtr output) -{ - /* go to the hw and retrieve a new output struct */ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmmode_ptr drmmode = drmmode_output->drmmode; - xf86OutputStatus status; - drmModeFreeConnector(drmmode_output->mode_output); - - drmmode_output->mode_output = - drmModeGetConnector(drmmode->fd, drmmode_output->output_id); - - switch (drmmode_output->mode_output->connection) { - case DRM_MODE_CONNECTED: - status = XF86OutputStatusConnected; - break; - case DRM_MODE_DISCONNECTED: - status = XF86OutputStatusDisconnected; - break; - default: - case DRM_MODE_UNKNOWNCONNECTION: - status = XF86OutputStatusUnknown; - break; - } - return status; -} - -static Bool -drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr koutput = drmmode_output->mode_output; - struct fixed_panel_lvds *p_lvds = drmmode_output->private_data; - - /* - * If the connector type is LVDS, we will use the panel limit to - * verfiy whether the mode is valid. - */ - if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { - if (pModes->HDisplay > p_lvds->hdisplay || - pModes->VDisplay > p_lvds->vdisplay) - return MODE_PANEL; - else - return MODE_OK; - } - return MODE_OK; -} - -static DisplayModePtr -drmmode_output_lvds_edid(xf86OutputPtr output, DisplayModePtr modes) -{ - xf86MonPtr mon = output->MonInfo; - - if (!mon || !GTF_SUPPORTED(mon->features.msc)) { - DisplayModePtr i, m, p = NULL; - int max_x = 0, max_y = 0; - float max_vrefresh = 0.0; - - for (m = modes; m; m = m->next) { - if (m->type & M_T_PREFERRED) - p = m; - max_x = max(max_x, m->HDisplay); - max_y = max(max_y, m->VDisplay); - max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m)); - } - - max_vrefresh = max(max_vrefresh, 60.0); - max_vrefresh *= (1 + SYNC_TOLERANCE); - -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0) - m = xf86GetDefaultModes(); -#else - m = xf86GetDefaultModes(0,0); -#endif - - xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0); - - for (i = m; i; i = i->next) { - if (xf86ModeVRefresh(i) > max_vrefresh) - i->status = MODE_VSYNC; - if (p && i->HDisplay >= p->HDisplay && - i->VDisplay >= p->VDisplay && - xf86ModeVRefresh(i) >= xf86ModeVRefresh(p)) - i->status = MODE_VSYNC; - } - - xf86PruneInvalidModes(output->scrn, &m, FALSE); - - modes = xf86ModesAdd(modes, m); - } - - return modes; -} - -static DisplayModePtr -drmmode_output_get_modes(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr koutput = drmmode_output->mode_output; - drmmode_ptr drmmode = drmmode_output->drmmode; - int i; - DisplayModePtr Modes = NULL, Mode; - drmModePropertyPtr props; - struct fixed_panel_lvds *p_lvds; - drmModeModeInfo *mode_ptr; - - /* look for an EDID property */ - for (i = 0; i < koutput->count_props; i++) { - props = drmModeGetProperty(drmmode->fd, koutput->props[i]); - if (!props) - continue; - if (!(props->flags & DRM_MODE_PROP_BLOB)) { - drmModeFreeProperty(props); - continue; - } - - if (!strcmp(props->name, "EDID")) { - drmModeFreePropertyBlob(drmmode_output->edid_blob); - drmmode_output->edid_blob = - drmModeGetPropertyBlob(drmmode->fd, - koutput->prop_values[i]); - } - drmModeFreeProperty(props); - } - - if (drmmode_output->edid_blob) - xf86OutputSetEDID(output, - xf86InterpretEDID(output->scrn->scrnIndex, - drmmode_output->edid_blob->data)); - else - xf86OutputSetEDID(output, - xf86InterpretEDID(output->scrn->scrnIndex, - NULL)); - - /* modes should already be available */ - for (i = 0; i < koutput->count_modes; i++) { - Mode = xnfalloc(sizeof(DisplayModeRec)); - - drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], - Mode); - Modes = xf86ModesAdd(Modes, Mode); - - } - p_lvds = drmmode_output->private_data; - /* - * If the connector type is LVDS, we will traverse the kernel mode to - * get the panel limit. - * If it is incorrect, please fix me. - */ - if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { - p_lvds->hdisplay = 0; - p_lvds->vdisplay = 0; - for (i = 0; i < koutput->count_modes; i++) { - mode_ptr = &koutput->modes[i]; - if ((mode_ptr->hdisplay >= p_lvds->hdisplay) && - (mode_ptr->vdisplay >= p_lvds->vdisplay)) { - p_lvds->hdisplay = mode_ptr->hdisplay; - p_lvds->vdisplay = mode_ptr->vdisplay; - } - } - if (!p_lvds->hdisplay || !p_lvds->vdisplay) - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "Incorrect KMS mode.\n"); - } - - if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) - Modes = drmmode_output_lvds_edid(output, Modes); - - return Modes; -} - -static void -drmmode_output_destroy(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - int i; - - if (drmmode_output->edid_blob) - drmModeFreePropertyBlob(drmmode_output->edid_blob); - for (i = 0; i < drmmode_output->num_props; i++) { - drmModeFreeProperty(drmmode_output->props[i].mode_prop); - free(drmmode_output->props[i].atoms); - } - free(drmmode_output->props); - drmModeFreeConnector(drmmode_output->mode_output); - drmmode_output->mode_output = NULL; - if (drmmode_output->private_data) { - free(drmmode_output->private_data); - drmmode_output->private_data = NULL; - } - if (drmmode_output->backlight_iface) - drmmode_backlight_set(output, drmmode_output->backlight_active_level); - - list_del(&drmmode_output->link); - free(drmmode_output); - - output->driver_private = NULL; -} - -static void -drmmode_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - - if (!drmmode_output->backlight_iface) - return; - - if (mode == DPMSModeOn) { - /* If we're going from off->on we may need to turn on the backlight. */ - if (oldmode != DPMSModeOn) - drmmode_backlight_set(output, drmmode_output->backlight_active_level); - } else { - /* Only save the current backlight value if we're going from on to off. */ - if (oldmode == DPMSModeOn) - drmmode_output->backlight_active_level = drmmode_backlight_get(output); - drmmode_backlight_set(output, 0); - } -} - -static void -drmmode_output_dpms(xf86OutputPtr output, int mode) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr koutput = drmmode_output->mode_output; - drmmode_ptr drmmode = drmmode_output->drmmode; - int i; - drmModePropertyPtr props; - - for (i = 0; i < koutput->count_props; i++) { - props = drmModeGetProperty(drmmode->fd, koutput->props[i]); - if (!props) - continue; - - if (!strcmp(props->name, "DPMS")) { - drmModeConnectorSetProperty(drmmode->fd, - drmmode_output->output_id, - props->prop_id, - mode); - drmmode_output_dpms_backlight(output, - drmmode_output->dpms_mode, - mode); - drmmode_output->dpms_mode = mode; - drmModeFreeProperty(props); - return; - } - drmModeFreeProperty(props); - } -} - -int -drmmode_output_dpms_status(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - - return drmmode_output->dpms_mode; -} - -static Bool -drmmode_property_ignore(drmModePropertyPtr prop) -{ - if (!prop) - return TRUE; - /* ignore blob prop */ - if (prop->flags & DRM_MODE_PROP_BLOB) - return TRUE; - /* ignore standard property */ - if (!strcmp(prop->name, "EDID") || - !strcmp(prop->name, "DPMS")) - return TRUE; - - return FALSE; -} - -#define BACKLIGHT_NAME "Backlight" -#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT" -static Atom backlight_atom, backlight_deprecated_atom; - -static void -drmmode_output_create_resources(xf86OutputPtr output) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmModeConnectorPtr mode_output = drmmode_output->mode_output; - drmmode_ptr drmmode = drmmode_output->drmmode; - drmModePropertyPtr drmmode_prop; - int i, j, err; - - drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); - if (!drmmode_output->props) - return; - - drmmode_output->num_props = 0; - for (i = 0, j = 0; i < mode_output->count_props; i++) { - drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); - if (drmmode_property_ignore(drmmode_prop)) { - drmModeFreeProperty(drmmode_prop); - continue; - } - drmmode_output->props[j].mode_prop = drmmode_prop; - drmmode_output->props[j].value = mode_output->prop_values[i]; - drmmode_output->num_props++; - j++; - } - - for (i = 0; i < drmmode_output->num_props; i++) { - drmmode_prop_ptr p = &drmmode_output->props[i]; - drmmode_prop = p->mode_prop; - - if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { - INT32 range[2]; - - p->num_atoms = 1; - p->atoms = calloc(p->num_atoms, sizeof(Atom)); - if (!p->atoms) - continue; - p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); - range[0] = drmmode_prop->values[0]; - range[1] = drmmode_prop->values[1]; - err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], - FALSE, TRUE, - drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, - 2, range); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - } - err = RRChangeOutputProperty(output->randr_output, p->atoms[0], - XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - } - } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { - p->num_atoms = drmmode_prop->count_enums + 1; - p->atoms = calloc(p->num_atoms, sizeof(Atom)); - if (!p->atoms) - continue; - p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); - for (j = 1; j <= drmmode_prop->count_enums; j++) { - struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; - p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); - } - err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], - FALSE, FALSE, - drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, - p->num_atoms - 1, (INT32 *)&p->atoms[1]); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - } - for (j = 0; j < drmmode_prop->count_enums; j++) - if (drmmode_prop->enums[j].value == p->value) - break; - /* there's always a matching value */ - err = RRChangeOutputProperty(output->randr_output, p->atoms[0], - XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - } - } - } - - if (drmmode_output->backlight_iface) { - INT32 data, backlight_range[2]; - /* Set up the backlight property, which takes effect immediately - * and accepts values only within the backlight_range. */ - backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, TRUE); - backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME, - sizeof(BACKLIGHT_DEPRECATED_NAME) - 1, TRUE); - - backlight_range[0] = 0; - backlight_range[1] = drmmode_output->backlight_max; - err = RRConfigureOutputProperty(output->randr_output, backlight_atom, - FALSE, TRUE, FALSE, 2, backlight_range); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - } - err = RRConfigureOutputProperty(output->randr_output, backlight_deprecated_atom, - FALSE, TRUE, FALSE, 2, backlight_range); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - } - /* Set the current value of the backlight property */ - data = drmmode_output->backlight_active_level; - err = RRChangeOutputProperty(output->randr_output, backlight_atom, - XA_INTEGER, 32, PropModeReplace, 1, &data, - FALSE, TRUE); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - } - err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom, - XA_INTEGER, 32, PropModeReplace, 1, &data, - FALSE, TRUE); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - } - } -} - -static Bool -drmmode_output_set_property(xf86OutputPtr output, Atom property, - RRPropertyValuePtr value) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - drmmode_ptr drmmode = drmmode_output->drmmode; - int i; - - if (property == backlight_atom || property == backlight_deprecated_atom) { - INT32 val; - - if (value->type != XA_INTEGER || value->format != 32 || - value->size != 1) - { - return FALSE; - } - - val = *(INT32 *)value->data; - if (val < 0 || val > drmmode_output->backlight_max) - return FALSE; - - if (drmmode_output->dpms_mode == DPMSModeOn) - drmmode_backlight_set(output, val); - drmmode_output->backlight_active_level = val; - return TRUE; - } - - for (i = 0; i < drmmode_output->num_props; i++) { - drmmode_prop_ptr p = &drmmode_output->props[i]; - - if (p->atoms[0] != property) - continue; - - if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { - uint32_t val; - - if (value->type != XA_INTEGER || value->format != 32 || - value->size != 1) - return FALSE; - val = *(uint32_t *)value->data; - - drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, - p->mode_prop->prop_id, (uint64_t)val); - return TRUE; - } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { - Atom atom; - const char *name; - int j; - - if (value->type != XA_ATOM || value->format != 32 || value->size != 1) - return FALSE; - memcpy(&atom, value->data, 4); - name = NameForAtom(atom); - - /* search for matching name string, then set its value down */ - for (j = 0; j < p->mode_prop->count_enums; j++) { - if (!strcmp(p->mode_prop->enums[j].name, name)) { - drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, - p->mode_prop->prop_id, p->mode_prop->enums[j].value); - return TRUE; - } - } - return FALSE; - } - } - - return TRUE; -} - -static Bool -drmmode_output_get_property(xf86OutputPtr output, Atom property) -{ - drmmode_output_private_ptr drmmode_output = output->driver_private; - int err; - - if (property == backlight_atom || property == backlight_deprecated_atom) { - INT32 val; - - if (! drmmode_output->backlight_iface) - return FALSE; - - val = drmmode_backlight_get(output); - if (val < 0) - return FALSE; - err = RRChangeOutputProperty(output->randr_output, property, - XA_INTEGER, 32, PropModeReplace, 1, &val, - FALSE, TRUE); - if (err != 0) { - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - return FALSE; - } - - return TRUE; - } - - return TRUE; -} - -static const xf86OutputFuncsRec drmmode_output_funcs = { - .create_resources = drmmode_output_create_resources, -#ifdef RANDR_12_INTERFACE - .set_property = drmmode_output_set_property, - .get_property = drmmode_output_get_property, -#endif - .dpms = drmmode_output_dpms, -#if 0 - - .save = drmmode_crt_save, - .restore = drmmode_crt_restore, - .mode_fixup = drmmode_crt_mode_fixup, - .prepare = drmmode_output_prepare, - .mode_set = drmmode_crt_mode_set, - .commit = drmmode_output_commit, -#endif - .detect = drmmode_output_detect, - .mode_valid = drmmode_output_mode_valid, - - .get_modes = drmmode_output_get_modes, - .destroy = drmmode_output_destroy -}; - -static int subpixel_conv_table[7] = { 0, SubPixelUnknown, - SubPixelHorizontalRGB, - SubPixelHorizontalBGR, - SubPixelVerticalRGB, - SubPixelVerticalBGR, - SubPixelNone }; - -static const char *output_names[] = { "None", - "VGA", - "DVI", - "DVI", - "DVI", - "Composite", - "TV", - "LVDS", - "CTV", - "DIN", - "DP", - "HDMI", - "HDMI", -}; - - -static void -drmmode_output_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, int num) -{ - xf86OutputPtr output; - drmModeConnectorPtr koutput; - drmModeEncoderPtr kencoder; - drmmode_output_private_ptr drmmode_output; - char name[32]; - - koutput = drmModeGetConnector(drmmode->fd, - drmmode->mode_res->connectors[num]); - if (!koutput) - return; - - kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); - if (!kencoder) { - drmModeFreeConnector(koutput); - return; - } - - snprintf(name, 32, "%s%d", output_names[koutput->connector_type], - koutput->connector_type_id); - - output = xf86OutputCreate (scrn, &drmmode_output_funcs, name); - if (!output) { - drmModeFreeEncoder(kencoder); - drmModeFreeConnector(koutput); - return; - } - - drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); - if (!drmmode_output) { - xf86OutputDestroy(output); - drmModeFreeConnector(koutput); - drmModeFreeEncoder(kencoder); - return; - } - /* - * If the connector type of the output device is LVDS, we will - * allocate the private_data to store the panel limit. - * For example: hdisplay, vdisplay - */ - drmmode_output->private_data = NULL; - if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) { - drmmode_output->private_data = calloc( - sizeof(struct fixed_panel_lvds), 1); - if (!drmmode_output->private_data) - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "Can't allocate private memory for LVDS.\n"); - } - drmmode_output->output_id = drmmode->mode_res->connectors[num]; - drmmode_output->mode_output = koutput; - drmmode_output->mode_encoder = kencoder; - drmmode_output->drmmode = drmmode; - output->mm_width = koutput->mmWidth; - output->mm_height = koutput->mmHeight; - - output->subpixel_order = subpixel_conv_table[koutput->subpixel]; - output->driver_private = drmmode_output; - - if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) - drmmode_backlight_init(output); - - output->possible_crtcs = kencoder->possible_crtcs; - output->possible_clones = kencoder->possible_clones; - - drmmode_output->output = output; - list_add(&drmmode_output->link, &drmmode->outputs); -} - -static Bool -drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) -{ - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - drmmode_crtc_private_ptr - drmmode_crtc = xf86_config->crtc[0]->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - intel_screen_private *intel = intel_get_screen_private(scrn); - drm_intel_bo *old_front = NULL; - Bool ret; - ScreenPtr screen = screenInfo.screens[scrn->scrnIndex]; - PixmapPtr pixmap; - uint32_t old_fb_id; - int i, old_width, old_height, old_pitch; - unsigned long pitch; - - if (scrn->virtualX == width && scrn->virtualY == height) - return TRUE; - - old_width = scrn->virtualX; - old_height = scrn->virtualY; - old_pitch = scrn->displayWidth; - old_fb_id = drmmode->fb_id; - old_front = intel->front_buffer; - - intel->front_buffer = intel_allocate_framebuffer(scrn, - width, height, - intel->cpp, - &pitch); - if (!intel->front_buffer) - goto fail; - - ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, - scrn->bitsPerPixel, pitch, - intel->front_buffer->handle, - &drmmode->fb_id); - if (ret) - goto fail; - - scrn->virtualX = width; - scrn->virtualY = height; - scrn->displayWidth = pitch / intel->cpp; - - pixmap = screen->GetScreenPixmap(screen); - screen->ModifyPixmapHeader(pixmap, width, height, -1, -1, pitch, NULL); - intel_set_pixmap_bo(pixmap, intel->front_buffer); - intel_get_pixmap_private(pixmap)->busy = 1; - - for (i = 0; i < xf86_config->num_crtc; i++) { - xf86CrtcPtr crtc = xf86_config->crtc[i]; - - if (!crtc->enabled) - continue; - - if (!drmmode_apply(crtc)) - goto fail; - } - - if (old_fb_id) - drmModeRmFB(drmmode->fd, old_fb_id); - if (old_front) - drm_intel_bo_unreference(old_front); - - return TRUE; - - fail: - if (intel->front_buffer) - drm_intel_bo_unreference(intel->front_buffer); - intel->front_buffer = old_front; - scrn->virtualX = old_width; - scrn->virtualY = old_height; - scrn->displayWidth = old_pitch; - drmmode->fb_id = old_fb_id; - - return FALSE; -} - -Bool -drmmode_do_pageflip(ScreenPtr screen, dri_bo *new_front, void *data) -{ - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - intel_screen_private *intel = intel_get_screen_private(scrn); - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - unsigned int pitch = scrn->displayWidth * intel->cpp; - int i, old_fb_id; - - /* - * Create a new handle for the back buffer - */ - old_fb_id = drmmode->fb_id; - if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY, - scrn->depth, scrn->bitsPerPixel, pitch, - new_front->handle, &drmmode->fb_id)) - goto error_out; - - /* - * Queue flips on all enabled CRTCs - * Note that if/when we get per-CRTC buffers, we'll have to update this. - * Right now it assumes a single shared fb across all CRTCs, with the - * kernel fixing up the offset of each CRTC as necessary. - * - * Also, flips queued on disabled or incorrectly configured displays - * may never complete; this is a configuration error. - */ - for (i = 0; i < config->num_crtc; i++) { - xf86CrtcPtr crtc = config->crtc[i]; - - if (!crtc->enabled) - continue; - - drmmode_crtc = crtc->driver_private; - drmmode->event_data = data; - drmmode->flip_count++; - if (drmModePageFlip(drmmode->fd, crtc_id(drmmode_crtc), drmmode->fb_id, - DRM_MODE_PAGE_FLIP_EVENT, drmmode)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "flip queue failed: %s\n", strerror(errno)); - goto error_undo; - } - } - - drmmode->old_fb_id = old_fb_id; - - return TRUE; - -error_undo: - drmModeRmFB(drmmode->fd, drmmode->fb_id); - drmmode->fb_id = old_fb_id; - -error_out: - xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", - strerror(errno)); - return FALSE; -} - -static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { - drmmode_xf86crtc_resize -}; - -static void -drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event_data); -} - -static void -drmmode_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - drmmode_ptr drmmode = event_data; - - drmmode->flip_count--; - if (drmmode->flip_count > 0) - return; - - drmModeRmFB(drmmode->fd, drmmode->old_fb_id); - - I830DRI2FlipEventHandler(frame, tv_sec, tv_usec, drmmode->event_data); -} - -static void -drm_wakeup_handler(pointer data, int err, pointer p) -{ - drmmode_ptr drmmode = data; - fd_set *read_mask = p; - - if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) - drmHandleEvent(drmmode->fd, &drmmode->event_context); -} - -Bool drmmode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) -{ - intel_screen_private *intel = intel_get_screen_private(scrn); - struct drm_i915_getparam gp; - drmmode_ptr drmmode; - unsigned int i; - int has_flipping = 0; - - drmmode = xnfalloc(sizeof *drmmode); - drmmode->fd = fd; - drmmode->fb_id = 0; - - list_init(&drmmode->crtcs); - list_init(&drmmode->outputs); - - xf86CrtcConfigInit(scrn, &drmmode_xf86crtc_config_funcs); - - drmmode->cpp = cpp; - drmmode->mode_res = drmModeGetResources(drmmode->fd); - if (!drmmode->mode_res) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "failed to get resources: %s\n", strerror(errno)); - return FALSE; - } - - xf86CrtcSetSizeRange(scrn, 320, 200, drmmode->mode_res->max_width, - drmmode->mode_res->max_height); - for (i = 0; i < drmmode->mode_res->count_crtcs; i++) - drmmode_crtc_init(scrn, drmmode, i); - - for (i = 0; i < drmmode->mode_res->count_connectors; i++) - drmmode_output_init(scrn, drmmode, i); - - xf86InitialConfiguration(scrn, TRUE); - - gp.param = I915_PARAM_HAS_PAGEFLIPPING; - gp.value = &has_flipping; - (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, - sizeof(gp)); - if (has_flipping) { - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "Kernel page flipping support detected, enabling\n"); - intel->use_pageflipping = TRUE; - drmmode->flip_count = 0; - drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; - drmmode->event_context.vblank_handler = drmmode_vblank_handler; - drmmode->event_context.page_flip_handler = - drmmode_page_flip_handler; - AddGeneralSocket(fd); - RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, - drm_wakeup_handler, drmmode); - } - - intel->modes = drmmode; - return TRUE; -} - -void -drmmode_remove_fb(intel_screen_private *intel) -{ - drmmode_ptr drmmode = intel->modes; - - if (drmmode->fb_id) { - drmModeRmFB(drmmode->fd, drmmode->fb_id); - drmmode->fb_id = 0; - } -} - -void -drmmode_fini(intel_screen_private *intel) -{ - drmmode_ptr drmmode = intel->modes; - - while(!list_is_empty(&drmmode->crtcs)) { - xf86CrtcDestroy(list_first_entry(&drmmode->crtcs, - drmmode_crtc_private_rec, - link)->crtc); - } - - while(!list_is_empty(&drmmode->outputs)) { - xf86OutputDestroy(list_first_entry(&drmmode->outputs, - drmmode_output_private_rec, - link)->output); - } - - if (drmmode->fb_id) - drmModeRmFB(drmmode->fd, drmmode->fb_id); - - /* drmmode->rotate_fb_id should have been destroyed already */ - - free(drmmode); - intel->modes = NULL; -} - -int -drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc) -{ - return drm_intel_get_pipe_from_crtc_id (bufmgr, crtc_id(crtc->driver_private)); -} - -/* for the drmmode overlay */ -int -drmmode_crtc_id(xf86CrtcPtr crtc) -{ - return crtc_id(crtc->driver_private); -} diff --git a/src/intel.h b/src/intel.h index da7ca573..be1ae579 100644 --- a/src/intel.h +++ b/src/intel.h @@ -438,13 +438,15 @@ enum { DEBUG_FLUSH_WAIT = 0x4, }; -extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); -extern void drmmode_remove_fb(intel_screen_private *intel); -extern void drmmode_fini(intel_screen_private *intel); -extern int drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc); -extern int drmmode_crtc_id(xf86CrtcPtr crtc); -extern int drmmode_output_dpms_status(xf86OutputPtr output); -extern Bool drmmode_do_pageflip(ScreenPtr screen, dri_bo *new_front, void *data); +extern Bool intel_mode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); +extern void intel_mode_remove_fb(intel_screen_private *intel); +extern void intel_mode_fini(intel_screen_private *intel); + +extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc); +extern int intel_crtc_id(xf86CrtcPtr crtc); +extern int intel_output_dpms_status(xf86OutputPtr output); + +extern Bool intel_do_pageflip(ScreenPtr screen, dri_bo *new_front, void *data); static inline intel_screen_private * intel_get_screen_private(ScrnInfoPtr scrn) @@ -485,7 +487,11 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *user_data); extern Bool intel_crtc_on(xf86CrtcPtr crtc); -extern int intel_crtc_to_pipe(xf86CrtcPtr crtc); +static inline int intel_crtc_to_pipe(xf86CrtcPtr crtc) +{ + intel_screen_private *intel = intel_get_screen_private(crtc->scrn); + return intel_get_pipe_from_crtc_id(intel->bufmgr, crtc); +} /* intel_memory.c */ unsigned long intel_get_fence_size(intel_screen_private *intel, unsigned long size); diff --git a/src/intel_display.c b/src/intel_display.c new file mode 100644 index 00000000..9379217e --- /dev/null +++ b/src/intel_display.c @@ -0,0 +1,1582 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Dave Airlie + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "xorgVersion.h" + +#include "intel.h" +#include "intel_bufmgr.h" +#include "xf86drmMode.h" +#include "X11/Xatom.h" + +struct intel_mode { + int fd; + uint32_t fb_id; + drmModeResPtr mode_res; + int cpp; + + drmEventContext event_context; + void *event_data; + int old_fb_id; + int flip_count; + + struct list outputs; + struct list crtcs; +}; + +struct intel_crtc { + struct intel_mode *mode; + drmModeModeInfo kmode; + drmModeCrtcPtr mode_crtc; + dri_bo *cursor; + dri_bo *rotate_bo; + uint32_t rotate_pitch; + uint32_t rotate_fb_id; + xf86CrtcPtr crtc; + struct list link; +}; + +struct intel_property { + drmModePropertyPtr mode_prop; + uint64_t value; + int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ + Atom *atoms; +}; + +struct fixed_panel_lvds { + int hdisplay; + int vdisplay; +}; + +struct intel_output { + struct intel_mode *mode; + int output_id; + drmModeConnectorPtr mode_output; + drmModeEncoderPtr mode_encoder; + drmModePropertyBlobPtr edid_blob; + int num_props; + struct intel_property *props; + void *private_data; + int dpms_mode; + const char *backlight_iface; + int backlight_active_level; + int backlight_max; + xf86OutputPtr output; + struct list link; +}; + +static void +intel_output_dpms(xf86OutputPtr output, int mode); + +#define BACKLIGHT_CLASS "/sys/class/backlight" + +/* + * List of available kernel interfaces in priority order + */ +static const char *backlight_interfaces[] = { + "asus-laptop", + "eeepc", + "thinkpad_screen", + "mbp_backlight", + "acpi_video1", + "acpi_video0", + "fujitsu-laptop", + "sony", + "samsung", + NULL, +}; +/* + * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table + + * '/' + "max_backlight" + */ +#define BACKLIGHT_PATH_LEN 80 +/* Enough for 10 digits of backlight + '\n' + '\0' */ +#define BACKLIGHT_VALUE_LEN 12 + +static inline int +crtc_id(struct intel_crtc *crtc) +{ + return crtc->mode_crtc->crtc_id; +} + +static void +intel_output_backlight_set(xf86OutputPtr output, int level) +{ + struct intel_output *intel_output = output->driver_private; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd, len, ret; + + if (level > intel_output->backlight_max) + level = intel_output->backlight_max; + if (! intel_output->backlight_iface || level < 0) + return; + + len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); + sprintf(path, "%s/%s/brightness", + BACKLIGHT_CLASS, intel_output->backlight_iface); + fd = open(path, O_RDWR); + if (fd == -1) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight " + "control: %s\n", path, strerror(errno)); + return; + } + + ret = write(fd, val, len); + if (ret == -1) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight " + "control failed: %s\n", path, strerror(errno)); + } + + close(fd); +} + +static int +intel_output_backlight_get(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd, level; + + if (! intel_output->backlight_iface) + return -1; + + sprintf(path, "%s/%s/actual_brightness", + BACKLIGHT_CLASS, intel_output->backlight_iface); + fd = open(path, O_RDONLY); + if (fd == -1) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " + "for backlight control: %s\n", path, strerror(errno)); + return -1; + } + + memset(val, 0, sizeof(val)); + if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { + close(fd); + return -1; + } + + close(fd); + + level = atoi(val); + if (level > intel_output->backlight_max) + level = intel_output->backlight_max; + if (level < 0) + level = -1; + return level; +} + +static int +intel_output_backlight_get_max(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd, max = 0; + + sprintf(path, "%s/%s/max_brightness", + BACKLIGHT_CLASS, intel_output->backlight_iface); + fd = open(path, O_RDONLY); + if (fd == -1) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " + "for backlight control: %s\n", path, strerror(errno)); + return 0; + } + + memset(val, 0, sizeof(val)); + if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { + close(fd); + return -1; + } + + close(fd); + + max = atoi(val); + if (max <= 0) + max = -1; + return max; +} + +static void +intel_output_backlight_init(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + char path[BACKLIGHT_PATH_LEN]; + struct stat buf; + int i; + + for (i = 0; backlight_interfaces[i] != NULL; i++) { + sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]); + if (!stat(path, &buf)) { + intel_output->backlight_iface = backlight_interfaces[i]; + intel_output->backlight_max = intel_output_backlight_get_max(output); + intel_output->backlight_active_level = intel_output_backlight_get(output); + if (intel_output->backlight_max > 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + "found backlight control interface %s\n", path); + return; + } + } + } + intel_output->backlight_iface = NULL; +} + + +static void +mode_from_kmode(ScrnInfoPtr scrn, + drmModeModeInfoPtr kmode, + DisplayModePtr mode) +{ + memset(mode, 0, sizeof(DisplayModeRec)); + mode->status = MODE_OK; + + mode->Clock = kmode->clock; + + mode->HDisplay = kmode->hdisplay; + mode->HSyncStart = kmode->hsync_start; + mode->HSyncEnd = kmode->hsync_end; + mode->HTotal = kmode->htotal; + mode->HSkew = kmode->hskew; + + mode->VDisplay = kmode->vdisplay; + mode->VSyncStart = kmode->vsync_start; + mode->VSyncEnd = kmode->vsync_end; + mode->VTotal = kmode->vtotal; + mode->VScan = kmode->vscan; + + mode->Flags = kmode->flags; //& FLAG_BITS; + mode->name = strdup(kmode->name); + + if (kmode->type & DRM_MODE_TYPE_DRIVER) + mode->type = M_T_DRIVER; + if (kmode->type & DRM_MODE_TYPE_PREFERRED) + mode->type |= M_T_PREFERRED; + + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + +static void +mode_to_kmode(ScrnInfoPtr scrn, + drmModeModeInfoPtr kmode, + DisplayModePtr mode) +{ + memset(kmode, 0, sizeof(*kmode)); + + kmode->clock = mode->Clock; + kmode->hdisplay = mode->HDisplay; + kmode->hsync_start = mode->HSyncStart; + kmode->hsync_end = mode->HSyncEnd; + kmode->htotal = mode->HTotal; + kmode->hskew = mode->HSkew; + + kmode->vdisplay = mode->VDisplay; + kmode->vsync_start = mode->VSyncStart; + kmode->vsync_end = mode->VSyncEnd; + kmode->vtotal = mode->VTotal; + kmode->vscan = mode->VScan; + + kmode->flags = mode->Flags; //& FLAG_BITS; + if (mode->name) + strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); + kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} + +static void +intel_crtc_dpms(xf86CrtcPtr intel_crtc, int mode) +{ + +} + +static Bool +intel_crtc_apply(xf86CrtcPtr crtc) +{ + ScrnInfoPtr scrn = crtc->scrn; + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + uint32_t *output_ids; + int output_count = 0; + int fb_id, x, y; + int i, ret; + + output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); + if (!output_ids) + return FALSE; + + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + struct intel_output *intel_output; + + if (output->crtc != crtc) + continue; + + intel_output = output->driver_private; + output_ids[output_count] = + intel_output->mode_output->connector_id; + output_count++; + } + +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) + if (!xf86CrtcRotate(crtc, mode, rotation)) + goto done; +#else + if (!xf86CrtcRotate(crtc)) + goto done; +#endif + +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); +#endif + + + x = crtc->x; + y = crtc->y; + fb_id = mode->fb_id; + if (intel_crtc->rotate_fb_id) { + fb_id = intel_crtc->rotate_fb_id; + x = 0; + y = 0; + } + ret = drmModeSetCrtc(mode->fd, crtc_id(intel_crtc), + fb_id, x, y, output_ids, output_count, + &intel_crtc->kmode); + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set mode: %s\n", strerror(-ret)); + ret = FALSE; + } else + ret = TRUE; + + /* Turn on any outputs on this crtc that may have been disabled */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + intel_output_dpms(output, DPMSModeOn); + } + + intel_set_gem_max_sizes(scrn); + + if (scrn->pScreen) + xf86_reload_cursors(scrn->pScreen); + + return ret; + +done: + free(output_ids); + return FALSE; +} + +static Bool +intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + intel_screen_private *intel = intel_get_screen_private(scrn); + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *intel_mode = intel_crtc->mode; + int saved_x, saved_y; + Rotation saved_rotation; + DisplayModeRec saved_mode; + int ret = TRUE; + unsigned int pitch = scrn->displayWidth * intel->cpp; + + if (intel_mode->fb_id == 0) { + ret = drmModeAddFB(intel_mode->fd, + scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, + pitch, intel->front_buffer->handle, + &intel_mode->fb_id); + if (ret < 0) { + ErrorF("failed to add fb\n"); + return FALSE; + } + } + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + + mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode); + ret = intel_crtc_apply(crtc); + if (!ret) { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + } + return ret; +} + +static void +intel_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) +{ + +} + +static void +intel_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + + drmModeMoveCursor(mode->fd, crtc_id(intel_crtc), x, y); +} + +static void +intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + int ret; + + /* cursor should be mapped already */ + ret = dri_bo_subdata(intel_crtc->cursor, 0, 64*64*4, image); + if (ret) + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set cursor: %s\n", strerror(-ret)); +} + +static void +intel_crtc_hide_cursor(xf86CrtcPtr crtc) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + + drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 0, 64, 64); +} + +static void +intel_crtc_show_cursor(xf86CrtcPtr crtc) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + + drmModeSetCursor(mode->fd, crtc_id(intel_crtc), + intel_crtc->cursor->handle, 64, 64); +} + +static void * +intel_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) +{ + ScrnInfoPtr scrn = crtc->scrn; + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + unsigned long rotate_pitch; + int ret; + + intel_crtc->rotate_bo = intel_allocate_framebuffer(scrn, + width, height, + mode->cpp, + &rotate_pitch); + + if (!intel_crtc->rotate_bo) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow memory for rotated CRTC\n"); + return NULL; + } + + ret = drmModeAddFB(mode->fd, width, height, crtc->scrn->depth, + crtc->scrn->bitsPerPixel, rotate_pitch, + intel_crtc->rotate_bo->handle, + &intel_crtc->rotate_fb_id); + if (ret) { + ErrorF("failed to add rotate fb\n"); + drm_intel_bo_unreference(intel_crtc->rotate_bo); + return NULL; + } + + intel_crtc->rotate_pitch = rotate_pitch; + return intel_crtc->rotate_bo; +} + +static PixmapPtr +intel_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + ScrnInfoPtr scrn = crtc->scrn; + intel_screen_private *intel = intel_get_screen_private(scrn); + struct intel_crtc *intel_crtc = crtc->driver_private; + PixmapPtr rotate_pixmap; + + if (!data) { + data = intel_crtc_shadow_allocate (crtc, width, height); + if (!data) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + } + if (intel_crtc->rotate_bo == NULL) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + + rotate_pixmap = GetScratchPixmapHeader(scrn->pScreen, + width, height, + scrn->depth, + scrn->bitsPerPixel, + intel_crtc->rotate_pitch, + NULL); + + if (rotate_pixmap == NULL) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + return NULL; + } + + intel_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_bo); + + intel->shadow_present = TRUE; + + return rotate_pixmap; +} + +static void +intel_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + ScrnInfoPtr scrn = crtc->scrn; + intel_screen_private *intel = intel_get_screen_private(scrn); + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + + if (rotate_pixmap) { + intel_set_pixmap_bo(rotate_pixmap, NULL); + FreeScratchPixmapHeader(rotate_pixmap); + } + + if (data) { + /* Be sure to sync acceleration before the memory gets + * unbound. */ + drmModeRmFB(mode->fd, intel_crtc->rotate_fb_id); + intel_crtc->rotate_fb_id = 0; + dri_bo_unreference(intel_crtc->rotate_bo); + intel_crtc->rotate_bo = NULL; + } + intel->shadow_present = FALSE; +} + +static void +intel_crtc_gamma_set(xf86CrtcPtr crtc, + CARD16 *red, CARD16 *green, CARD16 *blue, int size) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_mode *mode = intel_crtc->mode; + + drmModeCrtcSetGamma(mode->fd, crtc_id(intel_crtc), + size, red, green, blue); +} + +static void +intel_crtc_destroy(xf86CrtcPtr crtc) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + + drm_intel_bo_unreference(intel_crtc->cursor); + intel_crtc->cursor = NULL; + + list_del(&intel_crtc->link); + free(intel_crtc); + + crtc->driver_private = NULL; +} + +static const xf86CrtcFuncsRec intel_crtc_funcs = { + .dpms = intel_crtc_dpms, + .set_mode_major = intel_crtc_set_mode_major, + .set_cursor_colors = intel_crtc_set_cursor_colors, + .set_cursor_position = intel_crtc_set_cursor_position, + .show_cursor = intel_crtc_show_cursor, + .hide_cursor = intel_crtc_hide_cursor, + .load_cursor_argb = intel_crtc_load_cursor_argb, + .shadow_create = intel_crtc_shadow_create, + .shadow_allocate = intel_crtc_shadow_allocate, + .shadow_destroy = intel_crtc_shadow_destroy, + .gamma_set = intel_crtc_gamma_set, + .destroy = intel_crtc_destroy, +}; + +static void +intel_crtc_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + xf86CrtcPtr crtc; + struct intel_crtc *intel_crtc; + + intel_crtc = calloc(sizeof(struct intel_crtc), 1); + if (intel_crtc == NULL) + return; + + crtc = xf86CrtcCreate(scrn, &intel_crtc_funcs); + if (crtc == NULL) { + free(intel_crtc); + return; + } + + intel_crtc->mode_crtc = drmModeGetCrtc(mode->fd, + mode->mode_res->crtcs[num]); + intel_crtc->mode = mode; + crtc->driver_private = intel_crtc; + + intel_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor", + HWCURSOR_SIZE_ARGB, + GTT_PAGE_SIZE); + drm_intel_bo_disable_reuse(intel_crtc->cursor); + + intel_crtc->crtc = crtc; + list_add(&intel_crtc->link, &mode->crtcs); +} + +static xf86OutputStatus +intel_output_detect(xf86OutputPtr output) +{ + /* go to the hw and retrieve a new output struct */ + struct intel_output *intel_output = output->driver_private; + struct intel_mode *mode = intel_output->mode; + xf86OutputStatus status; + drmModeFreeConnector(intel_output->mode_output); + + intel_output->mode_output = + drmModeGetConnector(mode->fd, intel_output->output_id); + + switch (intel_output->mode_output->connection) { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + break; + default: + case DRM_MODE_UNKNOWNCONNECTION: + status = XF86OutputStatusUnknown; + break; + } + return status; +} + +static Bool +intel_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) +{ + struct intel_output *intel_output = output->driver_private; + drmModeConnectorPtr koutput = intel_output->mode_output; + struct fixed_panel_lvds *p_lvds = intel_output->private_data; + + /* + * If the connector type is LVDS, we will use the panel limit to + * verfiy whether the mode is valid. + */ + if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { + if (pModes->HDisplay > p_lvds->hdisplay || + pModes->VDisplay > p_lvds->vdisplay) + return MODE_PANEL; + else + return MODE_OK; + } + return MODE_OK; +} + +static DisplayModePtr +intel_output_lvds_edid(xf86OutputPtr output, DisplayModePtr modes) +{ + xf86MonPtr mon = output->MonInfo; + + if (!mon || !GTF_SUPPORTED(mon->features.msc)) { + DisplayModePtr i, m, p = NULL; + int max_x = 0, max_y = 0; + float max_vrefresh = 0.0; + + for (m = modes; m; m = m->next) { + if (m->type & M_T_PREFERRED) + p = m; + max_x = max(max_x, m->HDisplay); + max_y = max(max_y, m->VDisplay); + max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m)); + } + + max_vrefresh = max(max_vrefresh, 60.0); + max_vrefresh *= (1 + SYNC_TOLERANCE); + +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0) + m = xf86GetDefaultModes(); +#else + m = xf86GetDefaultModes(0,0); +#endif + + xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0); + + for (i = m; i; i = i->next) { + if (xf86ModeVRefresh(i) > max_vrefresh) + i->status = MODE_VSYNC; + if (p && i->HDisplay >= p->HDisplay && + i->VDisplay >= p->VDisplay && + xf86ModeVRefresh(i) >= xf86ModeVRefresh(p)) + i->status = MODE_VSYNC; + } + + xf86PruneInvalidModes(output->scrn, &m, FALSE); + + modes = xf86ModesAdd(modes, m); + } + + return modes; +} + +static DisplayModePtr +intel_output_get_modes(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + drmModeConnectorPtr koutput = intel_output->mode_output; + struct intel_mode *mode = intel_output->mode; + int i; + DisplayModePtr Modes = NULL, Mode; + drmModePropertyPtr props; + struct fixed_panel_lvds *p_lvds; + drmModeModeInfo *mode_ptr; + + /* look for an EDID property */ + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(mode->fd, koutput->props[i]); + if (!props) + continue; + if (!(props->flags & DRM_MODE_PROP_BLOB)) { + drmModeFreeProperty(props); + continue; + } + + if (!strcmp(props->name, "EDID")) { + drmModeFreePropertyBlob(intel_output->edid_blob); + intel_output->edid_blob = + drmModeGetPropertyBlob(mode->fd, + koutput->prop_values[i]); + } + drmModeFreeProperty(props); + } + + if (intel_output->edid_blob) + xf86OutputSetEDID(output, + xf86InterpretEDID(output->scrn->scrnIndex, + intel_output->edid_blob->data)); + else + xf86OutputSetEDID(output, + xf86InterpretEDID(output->scrn->scrnIndex, + NULL)); + + /* modes should already be available */ + for (i = 0; i < koutput->count_modes; i++) { + Mode = xnfalloc(sizeof(DisplayModeRec)); + + mode_from_kmode(output->scrn, &koutput->modes[i], Mode); + Modes = xf86ModesAdd(Modes, Mode); + + } + p_lvds = intel_output->private_data; + /* + * If the connector type is LVDS, we will traverse the kernel mode to + * get the panel limit. + * If it is incorrect, please fix me. + */ + if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { + p_lvds->hdisplay = 0; + p_lvds->vdisplay = 0; + for (i = 0; i < koutput->count_modes; i++) { + mode_ptr = &koutput->modes[i]; + if ((mode_ptr->hdisplay >= p_lvds->hdisplay) && + (mode_ptr->vdisplay >= p_lvds->vdisplay)) { + p_lvds->hdisplay = mode_ptr->hdisplay; + p_lvds->vdisplay = mode_ptr->vdisplay; + } + } + if (!p_lvds->hdisplay || !p_lvds->vdisplay) + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "Incorrect KMS mode.\n"); + } + + if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) + Modes = intel_output_lvds_edid(output, Modes); + + return Modes; +} + +static void +intel_output_destroy(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + int i; + + if (intel_output->edid_blob) + drmModeFreePropertyBlob(intel_output->edid_blob); + for (i = 0; i < intel_output->num_props; i++) { + drmModeFreeProperty(intel_output->props[i].mode_prop); + free(intel_output->props[i].atoms); + } + free(intel_output->props); + drmModeFreeConnector(intel_output->mode_output); + intel_output->mode_output = NULL; + if (intel_output->private_data) { + free(intel_output->private_data); + intel_output->private_data = NULL; + } + if (intel_output->backlight_iface) + intel_output_backlight_set(output, + intel_output->backlight_active_level); + + list_del(&intel_output->link); + free(intel_output); + + output->driver_private = NULL; +} + +static void +intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode) +{ + struct intel_output *intel_output = output->driver_private; + + if (!intel_output->backlight_iface) + return; + + if (mode == DPMSModeOn) { + /* If we're going from off->on we may need to turn on the backlight. */ + if (oldmode != DPMSModeOn) + intel_output_backlight_set(output, + intel_output->backlight_active_level); + } else { + /* Only save the current backlight value if we're going from on to off. */ + if (oldmode == DPMSModeOn) + intel_output->backlight_active_level = intel_output_backlight_get(output); + intel_output_backlight_set(output, 0); + } +} + +static void +intel_output_dpms(xf86OutputPtr output, int dpms) +{ + struct intel_output *intel_output = output->driver_private; + drmModeConnectorPtr koutput = intel_output->mode_output; + struct intel_mode *mode = intel_output->mode; + int i; + drmModePropertyPtr props; + + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(mode->fd, koutput->props[i]); + if (!props) + continue; + + if (!strcmp(props->name, "DPMS")) { + drmModeConnectorSetProperty(mode->fd, + intel_output->output_id, + props->prop_id, + dpms); + intel_output_dpms_backlight(output, + intel_output->dpms_mode, + dpms); + intel_output->dpms_mode = dpms; + drmModeFreeProperty(props); + return; + } + drmModeFreeProperty(props); + } +} + +int +intel_output_dpms_status(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + return intel_output->dpms_mode; +} + +static Bool +intel_property_ignore(drmModePropertyPtr prop) +{ + if (!prop) + return TRUE; + + /* ignore blob prop */ + if (prop->flags & DRM_MODE_PROP_BLOB) + return TRUE; + + /* ignore standard property */ + if (!strcmp(prop->name, "EDID") || + !strcmp(prop->name, "DPMS")) + return TRUE; + + return FALSE; +} + +#define BACKLIGHT_NAME "Backlight" +#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT" +static Atom backlight_atom, backlight_deprecated_atom; + +static void +intel_output_create_resources(xf86OutputPtr output) +{ + struct intel_output *intel_output = output->driver_private; + drmModeConnectorPtr mode_output = intel_output->mode_output; + struct intel_mode *mode = intel_output->mode; + drmModePropertyPtr drmmode_prop; + int i, j, err; + + intel_output->props = calloc(mode_output->count_props, + sizeof(struct intel_property)); + if (!intel_output->props) + return; + + intel_output->num_props = 0; + for (i = 0, j = 0; i < mode_output->count_props; i++) { + drmmode_prop = drmModeGetProperty(mode->fd, mode_output->props[i]); + if (intel_property_ignore(drmmode_prop)) { + drmModeFreeProperty(drmmode_prop); + continue; + } + + intel_output->props[j].mode_prop = drmmode_prop; + intel_output->props[j].value = mode_output->prop_values[i]; + j++; + } + intel_output->num_props = j; + + for (i = 0; i < intel_output->num_props; i++) { + struct intel_property *p = &intel_output->props[i]; + drmmode_prop = p->mode_prop; + + if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { + INT32 range[2]; + + p->num_atoms = 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + range[0] = drmmode_prop->values[0]; + range[1] = drmmode_prop->values[1]; + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, TRUE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + 2, range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { + p->num_atoms = drmmode_prop->count_enums + 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + for (j = 1; j <= drmmode_prop->count_enums; j++) { + struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; + p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); + } + + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, FALSE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + p->num_atoms - 1, (INT32 *)&p->atoms[1]); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + + for (j = 0; j < drmmode_prop->count_enums; j++) + if (drmmode_prop->enums[j].value == p->value) + break; + /* there's always a matching value */ + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + } + + if (intel_output->backlight_iface) { + INT32 data, backlight_range[2]; + + /* Set up the backlight property, which takes effect + * immediately and accepts values only within the + * backlight_range. + */ + backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, TRUE); + backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME, + sizeof(BACKLIGHT_DEPRECATED_NAME) - 1, TRUE); + + backlight_range[0] = 0; + backlight_range[1] = intel_output->backlight_max; + err = RRConfigureOutputProperty(output->randr_output, + backlight_atom, + FALSE, TRUE, FALSE, + 2, backlight_range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRConfigureOutputProperty(output->randr_output, + backlight_deprecated_atom, + FALSE, TRUE, FALSE, + 2, backlight_range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + data = intel_output->backlight_active_level; + err = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } +} + +static Bool +intel_output_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_mode *mode = intel_output->mode; + int i; + + if (property == backlight_atom || property == backlight_deprecated_atom) { + INT32 val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < 0 || val > intel_output->backlight_max) + return FALSE; + + if (intel_output->dpms_mode == DPMSModeOn) + intel_output_backlight_set(output, val); + intel_output->backlight_active_level = val; + return TRUE; + } + + for (i = 0; i < intel_output->num_props; i++) { + struct intel_property *p = &intel_output->props[i]; + + if (p->atoms[0] != property) + continue; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + uint32_t val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + val = *(uint32_t *)value->data; + + drmModeConnectorSetProperty(mode->fd, intel_output->output_id, + p->mode_prop->prop_id, (uint64_t)val); + return TRUE; + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + Atom atom; + const char *name; + int j; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + memcpy(&atom, value->data, 4); + name = NameForAtom(atom); + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (!strcmp(p->mode_prop->enums[j].name, name)) { + drmModeConnectorSetProperty(mode->fd, intel_output->output_id, + p->mode_prop->prop_id, p->mode_prop->enums[j].value); + return TRUE; + } + } + return FALSE; + } + } + + return TRUE; +} + +static Bool +intel_output_get_property(xf86OutputPtr output, Atom property) +{ + struct intel_output *intel_output = output->driver_private; + int err; + + if (property == backlight_atom || property == backlight_deprecated_atom) { + INT32 val; + + if (! intel_output->backlight_iface) + return FALSE; + + val = intel_output_backlight_get(output); + if (val < 0) + return FALSE; + + err = RRChangeOutputProperty(output->randr_output, property, + XA_INTEGER, 32, PropModeReplace, 1, &val, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + return FALSE; + } + + return TRUE; + } + + return TRUE; +} + +static const xf86OutputFuncsRec intel_output_funcs = { + .create_resources = intel_output_create_resources, +#ifdef RANDR_12_INTERFACE + .set_property = intel_output_set_property, + .get_property = intel_output_get_property, +#endif + .dpms = intel_output_dpms, +#if 0 + + .save = drmmode_crt_save, + .restore = drmmode_crt_restore, + .mode_fixup = drmmode_crt_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = drmmode_crt_mode_set, + .commit = intel_output_commit, +#endif + .detect = intel_output_detect, + .mode_valid = intel_output_mode_valid, + + .get_modes = intel_output_get_modes, + .destroy = intel_output_destroy +}; + +static const int subpixel_conv_table[7] = { + 0, + SubPixelUnknown, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone +}; + +static const char *output_names[] = { + "None", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "TV", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", +}; + +static void +intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num) +{ + xf86OutputPtr output; + drmModeConnectorPtr koutput; + drmModeEncoderPtr kencoder; + struct intel_output *intel_output; + char name[32]; + + koutput = drmModeGetConnector(mode->fd, + mode->mode_res->connectors[num]); + if (!koutput) + return; + + kencoder = drmModeGetEncoder(mode->fd, koutput->encoders[0]); + if (!kencoder) { + drmModeFreeConnector(koutput); + return; + } + + snprintf(name, 32, "%s%d", output_names[koutput->connector_type], + koutput->connector_type_id); + + output = xf86OutputCreate (scrn, &intel_output_funcs, name); + if (!output) { + drmModeFreeEncoder(kencoder); + drmModeFreeConnector(koutput); + return; + } + + intel_output = calloc(sizeof(struct intel_output), 1); + if (!intel_output) { + xf86OutputDestroy(output); + drmModeFreeConnector(koutput); + drmModeFreeEncoder(kencoder); + return; + } + /* + * If the connector type of the output device is LVDS, we will + * allocate the private_data to store the panel limit. + * For example: hdisplay, vdisplay + */ + intel_output->private_data = NULL; + if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) { + intel_output->private_data = calloc( + sizeof(struct fixed_panel_lvds), 1); + if (!intel_output->private_data) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Can't allocate private memory for LVDS.\n"); + } + intel_output->output_id = mode->mode_res->connectors[num]; + intel_output->mode_output = koutput; + intel_output->mode_encoder = kencoder; + intel_output->mode = mode; + output->mm_width = koutput->mmWidth; + output->mm_height = koutput->mmHeight; + + output->subpixel_order = subpixel_conv_table[koutput->subpixel]; + output->driver_private = intel_output; + + if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) + intel_output_backlight_init(output); + + output->possible_crtcs = kencoder->possible_crtcs; + output->possible_clones = kencoder->possible_clones; + + intel_output->output = output; + list_add(&intel_output->link, &mode->outputs); +} + +static Bool +intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + struct intel_crtc *intel_crtc = xf86_config->crtc[0]->driver_private; + struct intel_mode *mode = intel_crtc->mode; + intel_screen_private *intel = intel_get_screen_private(scrn); + drm_intel_bo *old_front = NULL; + Bool ret; + ScreenPtr screen = screenInfo.screens[scrn->scrnIndex]; + PixmapPtr pixmap; + uint32_t old_fb_id; + int i, old_width, old_height, old_pitch; + unsigned long pitch; + + if (scrn->virtualX == width && scrn->virtualY == height) + return TRUE; + + old_width = scrn->virtualX; + old_height = scrn->virtualY; + old_pitch = scrn->displayWidth; + old_fb_id = mode->fb_id; + old_front = intel->front_buffer; + + intel->front_buffer = intel_allocate_framebuffer(scrn, + width, height, + intel->cpp, + &pitch); + if (!intel->front_buffer) + goto fail; + + ret = drmModeAddFB(mode->fd, width, height, scrn->depth, + scrn->bitsPerPixel, pitch, + intel->front_buffer->handle, + &mode->fb_id); + if (ret) + goto fail; + + scrn->virtualX = width; + scrn->virtualY = height; + scrn->displayWidth = pitch / intel->cpp; + + pixmap = screen->GetScreenPixmap(screen); + screen->ModifyPixmapHeader(pixmap, width, height, -1, -1, pitch, NULL); + intel_set_pixmap_bo(pixmap, intel->front_buffer); + intel_get_pixmap_private(pixmap)->busy = 1; + + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + + if (!crtc->enabled) + continue; + + if (!intel_crtc_apply(crtc)) + goto fail; + } + + if (old_fb_id) + drmModeRmFB(mode->fd, old_fb_id); + if (old_front) + drm_intel_bo_unreference(old_front); + + return TRUE; + +fail: + if (intel->front_buffer) + drm_intel_bo_unreference(intel->front_buffer); + intel->front_buffer = old_front; + scrn->virtualX = old_width; + scrn->virtualY = old_height; + scrn->displayWidth = old_pitch; + mode->fb_id = old_fb_id; + + return FALSE; +} + +Bool +intel_do_pageflip(ScreenPtr screen, dri_bo *new_front, void *data) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + intel_screen_private *intel = intel_get_screen_private(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + struct intel_crtc *crtc = config->crtc[0]->driver_private; + struct intel_mode *mode = crtc->mode; + unsigned int pitch = scrn->displayWidth * intel->cpp; + int i, old_fb_id; + + /* + * Create a new handle for the back buffer + */ + old_fb_id = mode->fb_id; + if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, pitch, + new_front->handle, &mode->fb_id)) + goto error_out; + + /* + * Queue flips on all enabled CRTCs + * Note that if/when we get per-CRTC buffers, we'll have to update this. + * Right now it assumes a single shared fb across all CRTCs, with the + * kernel fixing up the offset of each CRTC as necessary. + * + * Also, flips queued on disabled or incorrectly configured displays + * may never complete; this is a configuration error. + */ + for (i = 0; i < config->num_crtc; i++) { + if (!config->crtc[i]->enabled) + continue; + + mode->event_data = data; + mode->flip_count++; + if (drmModePageFlip(mode->fd, + crtc_id(config->crtc[i]->driver_private), + mode->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, mode)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(errno)); + goto error_undo; + } + } + + mode->old_fb_id = old_fb_id; + return TRUE; + +error_undo: + drmModeRmFB(mode->fd, mode->fb_id); + mode->fb_id = old_fb_id; + +error_out: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", + strerror(errno)); + return FALSE; +} + +static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = { + intel_xf86crtc_resize +}; + +static void +intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event_data); +} + +static void +intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + struct intel_mode *mode = event_data; + + mode->flip_count--; + if (mode->flip_count > 0) + return; + + drmModeRmFB(mode->fd, mode->old_fb_id); + + I830DRI2FlipEventHandler(frame, tv_sec, tv_usec, mode->event_data); +} + +static void +drm_wakeup_handler(pointer data, int err, pointer p) +{ + struct intel_mode *mode = data; + fd_set *read_mask = p; + + if (err >= 0 && FD_ISSET(mode->fd, read_mask)) + drmHandleEvent(mode->fd, &mode->event_context); +} + +Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + struct drm_i915_getparam gp; + struct intel_mode *mode; + unsigned int i; + int has_flipping = 0; + + mode = xnfalloc(sizeof *mode); + mode->fd = fd; + mode->fb_id = 0; + + list_init(&mode->crtcs); + list_init(&mode->outputs); + + xf86CrtcConfigInit(scrn, &intel_xf86crtc_config_funcs); + + mode->cpp = cpp; + mode->mode_res = drmModeGetResources(mode->fd); + if (!mode->mode_res) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to get resources: %s\n", strerror(errno)); + return FALSE; + } + + xf86CrtcSetSizeRange(scrn, 320, 200, mode->mode_res->max_width, + mode->mode_res->max_height); + for (i = 0; i < mode->mode_res->count_crtcs; i++) + intel_crtc_init(scrn, mode, i); + + for (i = 0; i < mode->mode_res->count_connectors; i++) + intel_output_init(scrn, mode, i); + + xf86InitialConfiguration(scrn, TRUE); + + gp.param = I915_PARAM_HAS_PAGEFLIPPING; + gp.value = &has_flipping; + (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, + sizeof(gp)); + if (has_flipping) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Kernel page flipping support detected, enabling\n"); + intel->use_pageflipping = TRUE; + mode->flip_count = 0; + mode->event_context.version = DRM_EVENT_CONTEXT_VERSION; + mode->event_context.vblank_handler = intel_vblank_handler; + mode->event_context.page_flip_handler = intel_page_flip_handler; + AddGeneralSocket(fd); + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, + drm_wakeup_handler, mode); + } + + intel->modes = mode; + return TRUE; +} + +void +intel_mode_remove_fb(intel_screen_private *intel) +{ + struct intel_mode *mode = intel->modes; + + if (mode->fb_id) { + drmModeRmFB(mode->fd, mode->fb_id); + mode->fb_id = 0; + } +} + +void +intel_mode_fini(intel_screen_private *intel) +{ + struct intel_mode *mode = intel->modes; + + while(!list_is_empty(&mode->crtcs)) { + xf86CrtcDestroy(list_first_entry(&mode->crtcs, + struct intel_crtc, + link)->crtc); + } + + while(!list_is_empty(&mode->outputs)) { + xf86OutputDestroy(list_first_entry(&mode->outputs, + struct intel_output, + link)->output); + } + + if (mode->fb_id) + drmModeRmFB(mode->fd, mode->fb_id); + + /* mode->rotate_fb_id should have been destroyed already */ + + free(mode); + intel->modes = NULL; +} + +int +intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc) +{ + return drm_intel_get_pipe_from_crtc_id(bufmgr, + crtc_id(crtc->driver_private)); +} + +/* for the mode overlay */ +int +intel_crtc_id(xf86CrtcPtr crtc) +{ + return crtc_id(crtc->driver_private); +} diff --git a/src/intel_driver.c b/src/intel_driver.c index d09c4328..1ef16ed4 100644 --- a/src/intel_driver.c +++ b/src/intel_driver.c @@ -599,7 +599,7 @@ static Bool I830PreInit(ScrnInfoPtr scrn, int flags) return FALSE; } - if (!drmmode_pre_init(scrn, intel->drmSubFD, intel->cpp)) { + if (!intel_mode_pre_init(scrn, intel->drmSubFD, intel->cpp)) { PreInitCleanup(scrn); return FALSE; } @@ -762,7 +762,7 @@ Bool intel_crtc_on(xf86CrtcPtr crtc) 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) + intel_output_dpms_status(output) == DPMSModeOn) active_outputs++; } @@ -771,14 +771,6 @@ Bool intel_crtc_on(xf86CrtcPtr crtc) 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 void intel_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data) @@ -1042,7 +1034,7 @@ static void I830FreeScreen(int scrnIndex, int flags) intel_screen_private *intel = intel_get_screen_private(scrn); if (intel) { - drmmode_fini(intel); + intel_mode_fini(intel); intel_close_drm_master(intel); intel_bufmgr_fini(intel); @@ -1122,7 +1114,7 @@ static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen) if (intel->front_buffer) { intel_set_pixmap_bo(screen->GetScreenPixmap(screen), NULL); - drmmode_remove_fb(intel); + intel_mode_remove_fb(intel); drm_intel_bo_unreference(intel->front_buffer); intel->front_buffer = NULL; } diff --git a/src/intel_video.c b/src/intel_video.c index a9d49429..d3d7cfdb 100644 --- a/src/intel_video.c +++ b/src/intel_video.c @@ -284,7 +284,7 @@ drmmode_overlay_put_image(intel_screen_private *intel, OVERLAY_DEBUG("off_Y: %i, off_U: %i, off_V: %i\n", request.offset_Y, request.offset_U, request.offset_V); - request.crtc_id = drmmode_crtc_id(crtc); + request.crtc_id = intel_crtc_id(crtc); request.dst_x = dstBox->x1; request.dst_y = dstBox->y1; request.dst_width = dstBox->x2 - dstBox->x1;