Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2007 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors:
     24  *    Dave Airlie <airlied (at) redhat.com>
     25  *
     26  */
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <sys/types.h>
     33 #include <sys/stat.h>
     34 #include <fcntl.h>
     35 #include <unistd.h>
     36 #include <errno.h>
     37 
     38 #include "xorg-server.h"
     39 #include "xorgVersion.h"
     40 
     41 #include "i830.h"
     42 #include "intel_bufmgr.h"
     43 #include "xf86drmMode.h"
     44 #include "X11/Xatom.h"
     45 
     46 typedef struct {
     47     int fd;
     48     uint32_t fb_id;
     49     drmModeResPtr mode_res;
     50     int cpp;
     51 } drmmode_rec, *drmmode_ptr;
     52 
     53 typedef struct {
     54     drmmode_ptr drmmode;
     55     drmModeCrtcPtr mode_crtc;
     56     dri_bo *cursor;
     57     dri_bo *rotate_bo;
     58     uint32_t rotate_fb_id;
     59 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
     60 
     61 typedef struct {
     62     drmModePropertyPtr mode_prop;
     63     uint64_t value;
     64     int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
     65     Atom *atoms;
     66 } drmmode_prop_rec, *drmmode_prop_ptr;
     67 
     68 struct fixed_panel_lvds {
     69 	int hdisplay;
     70 	int vdisplay;
     71 };
     72 typedef struct {
     73     drmmode_ptr drmmode;
     74     int output_id;
     75     drmModeConnectorPtr mode_output;
     76     drmModeEncoderPtr mode_encoder;
     77     drmModePropertyBlobPtr edid_blob;
     78     int num_props;
     79     drmmode_prop_ptr props;
     80     void *private_data;
     81     int dpms_mode;
     82     char *backlight_iface;
     83     int backlight_active_level;
     84     int backlight_max;
     85 } drmmode_output_private_rec, *drmmode_output_private_ptr;
     86 
     87 static void
     88 drmmode_output_dpms(xf86OutputPtr output, int mode);
     89 
     90 #define BACKLIGHT_CLASS "/sys/class/backlight"
     91 
     92 /*
     93  * List of available kernel interfaces in priority order
     94  */
     95 static char *backlight_interfaces[] = {
     96     "asus-laptop",
     97     "eeepc",
     98     "thinkpad_screen",
     99     "acpi_video1",
    100     "acpi_video0",
    101     "fujitsu-laptop",
    102     "sony",
    103     "samsung",
    104     NULL,
    105 };
    106 /*
    107  * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
    108  * '/' + "max_backlight"
    109  */
    110 #define BACKLIGHT_PATH_LEN 80
    111 /* Enough for 10 digits of backlight + '\n' + '\0' */
    112 #define BACKLIGHT_VALUE_LEN 12
    113 
    114 static void
    115 drmmode_backlight_set(xf86OutputPtr output, int level)
    116 {
    117     drmmode_output_private_ptr drmmode_output = output->driver_private;
    118     char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
    119     int fd, len, ret;
    120 
    121     if (level > drmmode_output->backlight_max)
    122 	level = drmmode_output->backlight_max;
    123     if (! drmmode_output->backlight_iface || level < 0)
    124 	return;
    125 
    126     len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
    127     sprintf(path, "%s/%s/brightness",
    128 	    BACKLIGHT_CLASS, drmmode_output->backlight_iface);
    129     fd = open(path, O_RDWR);
    130     if (fd == -1) {
    131 	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
    132 		   "control: %s\n", path, strerror(errno));
    133 	return;
    134     }
    135 
    136     ret = write(fd, val, len);
    137     if (ret == -1) {
    138 	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight "
    139 		   "control failed: %s\n", path, strerror(errno));
    140     }
    141 
    142     close(fd);
    143 }
    144 
    145 static int
    146 drmmode_backlight_get(xf86OutputPtr output)
    147 {
    148     drmmode_output_private_ptr drmmode_output = output->driver_private;
    149     char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
    150     int fd, level;
    151 
    152     if (! drmmode_output->backlight_iface)
    153 	return -1;
    154 
    155     sprintf(path, "%s/%s/actual_brightness",
    156 	    BACKLIGHT_CLASS, drmmode_output->backlight_iface);
    157     fd = open(path, O_RDONLY);
    158     if (fd == -1) {
    159 	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
    160 		   "for backlight control: %s\n", path, strerror(errno));
    161 	return -1;
    162     }
    163 
    164     memset(val, 0, sizeof(val));
    165     if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
    166 	close(fd);
    167 	return -1;
    168     }
    169 
    170     close(fd);
    171 
    172     level = atoi(val);
    173     if (level > drmmode_output->backlight_max)
    174 	level = drmmode_output->backlight_max;
    175     if (level < 0)
    176 	level = -1;
    177     return level;
    178 }
    179 
    180 static int
    181 drmmode_backlight_get_max(xf86OutputPtr output)
    182 {
    183     drmmode_output_private_ptr drmmode_output = output->driver_private;
    184     char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
    185     int fd, max = 0;
    186 
    187     sprintf(path, "%s/%s/max_brightness",
    188 	    BACKLIGHT_CLASS, drmmode_output->backlight_iface);
    189     fd = open(path, O_RDONLY);
    190     if (fd == -1) {
    191 	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
    192 		   "for backlight control: %s\n", path, strerror(errno));
    193 	return 0;
    194     }
    195 
    196     memset(val, 0, sizeof(val));
    197     if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
    198 	close(fd);
    199 	return -1;
    200     }
    201 
    202     close(fd);
    203 
    204     max = atoi(val);
    205     if (max <= 0)
    206 	max  = -1;
    207     return max;
    208 }
    209 
    210 static void
    211 drmmode_backlight_init(xf86OutputPtr output)
    212 {
    213     drmmode_output_private_ptr drmmode_output = output->driver_private;
    214     char path[BACKLIGHT_PATH_LEN];
    215     struct stat buf;
    216     int i;
    217 
    218     for (i = 0; backlight_interfaces[i] != NULL; i++) {
    219 	sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]);
    220 	if (!stat(path, &buf)) {
    221 	    drmmode_output->backlight_iface = backlight_interfaces[i];
    222 	    xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
    223 		       "found backlight control interface %s\n", path);
    224 	    drmmode_output->backlight_max = drmmode_backlight_get_max(output);
    225 	    drmmode_output->backlight_active_level = drmmode_backlight_get(output);
    226 	    return;
    227 	}
    228     }
    229     drmmode_output->backlight_iface = NULL;
    230 }
    231 
    232 
    233 static void
    234 drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
    235 			 drmModeModeInfoPtr kmode,
    236 			 DisplayModePtr	mode)
    237 {
    238 	memset(mode, 0, sizeof(DisplayModeRec));
    239 	mode->status = MODE_OK;
    240 
    241 	mode->Clock = kmode->clock;
    242 
    243 	mode->HDisplay = kmode->hdisplay;
    244 	mode->HSyncStart = kmode->hsync_start;
    245 	mode->HSyncEnd = kmode->hsync_end;
    246 	mode->HTotal = kmode->htotal;
    247 	mode->HSkew = kmode->hskew;
    248 
    249 	mode->VDisplay = kmode->vdisplay;
    250 	mode->VSyncStart = kmode->vsync_start;
    251 	mode->VSyncEnd = kmode->vsync_end;
    252 	mode->VTotal = kmode->vtotal;
    253 	mode->VScan = kmode->vscan;
    254 
    255 	mode->Flags = kmode->flags; //& FLAG_BITS;
    256 	mode->name = strdup(kmode->name);
    257 
    258 	if (kmode->type & DRM_MODE_TYPE_DRIVER)
    259 		mode->type = M_T_DRIVER;
    260 	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
    261 		mode->type |= M_T_PREFERRED;
    262 	xf86SetModeCrtc (mode, scrn->adjustFlags);
    263 }
    264 
    265 static void
    266 drmmode_ConvertToKMode(ScrnInfoPtr scrn,
    267 		       drmModeModeInfoPtr kmode,
    268 		       DisplayModePtr mode)
    269 {
    270 	memset(kmode, 0, sizeof(*kmode));
    271 
    272 	kmode->clock = mode->Clock;
    273 	kmode->hdisplay = mode->HDisplay;
    274 	kmode->hsync_start = mode->HSyncStart;
    275 	kmode->hsync_end = mode->HSyncEnd;
    276 	kmode->htotal = mode->HTotal;
    277 	kmode->hskew = mode->HSkew;
    278 
    279 	kmode->vdisplay = mode->VDisplay;
    280 	kmode->vsync_start = mode->VSyncStart;
    281 	kmode->vsync_end = mode->VSyncEnd;
    282 	kmode->vtotal = mode->VTotal;
    283 	kmode->vscan = mode->VScan;
    284 
    285 	kmode->flags = mode->Flags; //& FLAG_BITS;
    286 	if (mode->name)
    287 		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
    288 	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
    289 
    290 }
    291 
    292 static void
    293 drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
    294 {
    295 
    296 }
    297 
    298 static Bool
    299 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
    300 		       Rotation rotation, int x, int y)
    301 {
    302 	ScrnInfoPtr pScrn = crtc->scrn;
    303 	I830Ptr     pI830 = I830PTR(pScrn);
    304 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    305 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    306 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    307 	int saved_x, saved_y;
    308 	Rotation saved_rotation;
    309 	DisplayModeRec saved_mode;
    310 	uint32_t *output_ids;
    311 	int output_count = 0;
    312 	int ret = TRUE;
    313 	int i;
    314 	int fb_id;
    315 	drmModeModeInfo kmode;
    316 	unsigned int pitch = pScrn->displayWidth * pI830->cpp;
    317 
    318 	if (drmmode->fb_id == 0) {
    319 		ret = drmModeAddFB(drmmode->fd,
    320 				   pScrn->virtualX, pScrn->virtualY,
    321 				   pScrn->depth, pScrn->bitsPerPixel,
    322 				   pitch, pI830->front_buffer->bo->handle,
    323 				   &drmmode->fb_id);
    324 		if (ret < 0) {
    325 			ErrorF("failed to add fb\n");
    326 			return FALSE;
    327 		}
    328 	}
    329 
    330 	saved_mode = crtc->mode;
    331 	saved_x = crtc->x;
    332 	saved_y = crtc->y;
    333 	saved_rotation = crtc->rotation;
    334 
    335 	crtc->mode = *mode;
    336 	crtc->x = x;
    337 	crtc->y = y;
    338 	crtc->rotation = rotation;
    339 
    340 	output_ids = xcalloc(sizeof(uint32_t), xf86_config->num_output);
    341 	if (!output_ids) {
    342 		ret = FALSE;
    343 		goto done;
    344 	}
    345 
    346 	for (i = 0; i < xf86_config->num_output; i++) {
    347 		xf86OutputPtr output = xf86_config->output[i];
    348 		drmmode_output_private_ptr drmmode_output;
    349 
    350 		if (output->crtc != crtc)
    351 			continue;
    352 
    353 		drmmode_output = output->driver_private;
    354 		output_ids[output_count] =
    355 			drmmode_output->mode_output->connector_id;
    356 		output_count++;
    357 	}
    358 
    359 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0)
    360 	if (!xf86CrtcRotate(crtc, mode, rotation))
    361 		goto done;
    362 #else
    363 	if (!xf86CrtcRotate(crtc))
    364 		goto done;
    365 #endif
    366 
    367 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
    368 	crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
    369 			       crtc->gamma_blue, crtc->gamma_size);
    370 #endif
    371 
    372 	drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
    373 
    374 
    375 	fb_id = drmmode->fb_id;
    376 	if (drmmode_crtc->rotate_fb_id) {
    377 		fb_id = drmmode_crtc->rotate_fb_id;
    378 		x = 0;
    379 		y = 0;
    380 	}
    381 	ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    382 			     fb_id, x, y, output_ids, output_count, &kmode);
    383 	if (ret)
    384 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    385 			   "failed to set mode: %s", strerror(-ret));
    386 	else
    387 		ret = TRUE;
    388 
    389 	/* Turn on any outputs on this crtc that may have been disabled */
    390 	for (i = 0; i < xf86_config->num_output; i++) {
    391 		xf86OutputPtr output = xf86_config->output[i];
    392 
    393 		if (output->crtc != crtc)
    394 			continue;
    395 
    396 		drmmode_output_dpms(output, DPMSModeOn);
    397 	}
    398 
    399 	i830_set_max_gtt_map_size(pScrn);
    400 
    401 	if (pScrn->pScreen)
    402 		xf86_reload_cursors(pScrn->pScreen);
    403 done:
    404 	if (!ret) {
    405 		crtc->x = saved_x;
    406 		crtc->y = saved_y;
    407 		crtc->rotation = saved_rotation;
    408 		crtc->mode = saved_mode;
    409 	}
    410 	return ret;
    411 }
    412 
    413 static void
    414 drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
    415 {
    416 
    417 }
    418 
    419 static void
    420 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
    421 {
    422 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    423 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    424 
    425 	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
    426 }
    427 
    428 static void
    429 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
    430 {
    431 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    432 	int ret;
    433 
    434 	/* cursor should be mapped already */
    435 	ret = dri_bo_subdata(drmmode_crtc->cursor, 0, 64*64*4, image);
    436 	if (ret)
    437 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    438 			   "failed to set cursor: %s", strerror(-ret));
    439 
    440 	return;
    441 }
    442 
    443 
    444 static void
    445 drmmode_hide_cursor (xf86CrtcPtr crtc)
    446 {
    447 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    448 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    449 
    450 	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    451 			 0, 64, 64);
    452 }
    453 
    454 static void
    455 drmmode_show_cursor (xf86CrtcPtr crtc)
    456 {
    457 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    458 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    459 
    460 	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    461 			 drmmode_crtc->cursor->handle, 64, 64);
    462 }
    463 
    464 static void *
    465 drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
    466 {
    467 	ScrnInfoPtr pScrn = crtc->scrn;
    468 	I830Ptr pI830 = I830PTR(pScrn);
    469 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    470 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    471 	int size, ret;
    472 	unsigned long rotate_pitch;
    473 
    474 	width = i830_pad_drawable_width(width, drmmode->cpp);
    475 	rotate_pitch = width * drmmode->cpp;
    476 	size = rotate_pitch * height;
    477 
    478 	drmmode_crtc->rotate_bo =
    479 		drm_intel_bo_alloc(pI830->bufmgr, "rotate", size, 4096);
    480 
    481 	if (!drmmode_crtc->rotate_bo) {
    482 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    483 			   "Couldn't allocate shadow memory for rotated CRTC\n");
    484 		return NULL;
    485 	}
    486 
    487 	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
    488 			   crtc->scrn->bitsPerPixel, rotate_pitch,
    489 			   drmmode_crtc->rotate_bo->handle,
    490 			   &drmmode_crtc->rotate_fb_id);
    491 	if (ret) {
    492 		ErrorF("failed to add rotate fb\n");
    493 		drm_intel_bo_unreference(drmmode_crtc->rotate_bo);
    494 		return NULL;
    495 	}
    496 
    497 	return drmmode_crtc->rotate_bo;
    498 }
    499 
    500 static PixmapPtr
    501 drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
    502 {
    503 	ScrnInfoPtr pScrn = crtc->scrn;
    504 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    505 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    506 	unsigned long rotate_pitch;
    507 	PixmapPtr rotate_pixmap;
    508 
    509 	if (!data) {
    510 		data = drmmode_crtc_shadow_allocate (crtc, width, height);
    511 		if (!data) {
    512 			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    513 				   "Couldn't allocate shadow pixmap for rotated CRTC\n");
    514 			return NULL;
    515 		}
    516 	}
    517 
    518 	rotate_pitch =
    519 		i830_pad_drawable_width(width, drmmode->cpp) * drmmode->cpp;
    520 	rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
    521 					       width, height,
    522 					       pScrn->depth,
    523 					       pScrn->bitsPerPixel,
    524 					       rotate_pitch,
    525 					       NULL);
    526 
    527 	if (rotate_pixmap == NULL) {
    528 		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
    529 			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
    530 		return NULL;
    531 	}
    532 
    533 	if (drmmode_crtc->rotate_bo)
    534 		i830_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo);
    535 
    536 	return rotate_pixmap;
    537 }
    538 
    539 static void
    540 drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
    541 {
    542 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    543 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    544 
    545 	if (rotate_pixmap) {
    546 		i830_set_pixmap_bo(rotate_pixmap, NULL);
    547 		FreeScratchPixmapHeader(rotate_pixmap);
    548 	}
    549 
    550 
    551 	if (data) {
    552 		/* Be sure to sync acceleration before the memory gets
    553 		 * unbound. */
    554 		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
    555 		drmmode_crtc->rotate_fb_id = 0;
    556 		dri_bo_unreference(drmmode_crtc->rotate_bo);
    557 		drmmode_crtc->rotate_bo = NULL;
    558 	}
    559 }
    560 
    561 static void
    562 drmmode_crtc_gamma_set(xf86CrtcPtr crtc,
    563 		       CARD16 *red, CARD16 *green, CARD16 *blue, int size)
    564 {
    565 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    566 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    567 
    568 	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    569 			    size, red, green, blue);
    570 }
    571 
    572 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
    573 	.dpms = drmmode_crtc_dpms,
    574 	.set_mode_major = drmmode_set_mode_major,
    575 	.set_cursor_colors = drmmode_set_cursor_colors,
    576 	.set_cursor_position = drmmode_set_cursor_position,
    577 	.show_cursor = drmmode_show_cursor,
    578 	.hide_cursor = drmmode_hide_cursor,
    579 	.load_cursor_argb = drmmode_load_cursor_argb,
    580 	.shadow_create = drmmode_crtc_shadow_create,
    581 	.shadow_allocate = drmmode_crtc_shadow_allocate,
    582 	.shadow_destroy = drmmode_crtc_shadow_destroy,
    583 	.gamma_set = drmmode_crtc_gamma_set,
    584 	.destroy = NULL, /* XXX */
    585 };
    586 
    587 
    588 static void
    589 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
    590 {
    591 	xf86CrtcPtr crtc;
    592 	drmmode_crtc_private_ptr drmmode_crtc;
    593 
    594 	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
    595 	if (crtc == NULL)
    596 		return;
    597 
    598 	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
    599 	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
    600 						 drmmode->mode_res->crtcs[num]);
    601 	drmmode_crtc->drmmode = drmmode;
    602 	crtc->driver_private = drmmode_crtc;
    603 
    604 	return;
    605 }
    606 
    607 void
    608 drmmode_crtc_set_cursor_bo(xf86CrtcPtr crtc, dri_bo *cursor)
    609 {
    610 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    611 	drmmode_crtc->cursor = cursor;
    612 }
    613 
    614 static xf86OutputStatus
    615 drmmode_output_detect(xf86OutputPtr output)
    616 {
    617 	/* go to the hw and retrieve a new output struct */
    618 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    619 	drmmode_ptr drmmode = drmmode_output->drmmode;
    620 	xf86OutputStatus status;
    621 	drmModeFreeConnector(drmmode_output->mode_output);
    622 
    623 	drmmode_output->mode_output =
    624 		drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
    625 
    626 	switch (drmmode_output->mode_output->connection) {
    627 	case DRM_MODE_CONNECTED:
    628 		status = XF86OutputStatusConnected;
    629 		break;
    630 	case DRM_MODE_DISCONNECTED:
    631 		status = XF86OutputStatusDisconnected;
    632 		break;
    633 	default:
    634 	case DRM_MODE_UNKNOWNCONNECTION:
    635 		status = XF86OutputStatusUnknown;
    636 		break;
    637 	}
    638 	return status;
    639 }
    640 
    641 static Bool
    642 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
    643 {
    644 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    645 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    646 	struct fixed_panel_lvds *p_lvds = drmmode_output->private_data;
    647 
    648 	/*
    649 	 * If the connector type is LVDS, we will use the panel limit to
    650 	 * verfiy whether the mode is valid.
    651 	 */
    652 	if ((koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) && p_lvds) {
    653 		if (pModes->HDisplay > p_lvds->hdisplay ||
    654 			pModes->VDisplay > p_lvds->vdisplay)
    655 			return MODE_PANEL;
    656 		else
    657 			return MODE_OK;
    658 	}
    659 	return MODE_OK;
    660 }
    661 
    662 static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon,
    663 					DisplayModePtr mode)
    664 {
    665 	struct detailed_timings *timing = &det_mon->section.d_timings;
    666 
    667 	det_mon->type = DT;
    668 	timing->clock = mode->Clock * 1000;
    669 	timing->h_active = mode->HDisplay;
    670 	timing->h_blanking = mode->HTotal - mode->HDisplay;
    671 	timing->v_active = mode->VDisplay;
    672 	timing->v_blanking = mode->VTotal - mode->VDisplay;
    673 	timing->h_sync_off = mode->HSyncStart - mode->HDisplay;
    674 	timing->h_sync_width = mode->HSyncEnd - mode->HSyncStart;
    675 	timing->v_sync_off = mode->VSyncStart - mode->VDisplay;
    676 	timing->v_sync_width = mode->VSyncEnd - mode->VSyncStart;
    677 
    678 	if (mode->Flags & V_PVSYNC)
    679 		timing->misc |= 0x02;
    680 
    681 	if (mode->Flags & V_PHSYNC)
    682 		timing->misc |= 0x01;
    683 }
    684 
    685 static int drmmode_output_lvds_edid(xf86OutputPtr output,
    686 				struct fixed_panel_lvds *p_lvds)
    687 {
    688 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    689 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    690 	int i, j;
    691 	DisplayModePtr pmode;
    692 	xf86MonPtr	edid_mon;
    693 	drmModeModeInfo *mode_ptr;
    694 	struct detailed_monitor_section *det_mon;
    695 
    696 	if (output->MonInfo) {
    697 		/*
    698 		 * If there exists the EDID, we will either find a DS_RANGES
    699 		 * or replace a DS_VENDOR block, smashing it into a DS_RANGES
    700 		 * block with opern refresh to match all the default modes.
    701 		 */
    702 		int edid_det_block_num;
    703 		edid_mon = output->MonInfo;
    704 		edid_mon->features.msc |= 0x01;
    705 		j = -1;
    706 		edid_det_block_num = sizeof(edid_mon->det_mon) /
    707 					sizeof(edid_mon->det_mon[0]);
    708 		for (i = 0; i < edid_det_block_num; i++) {
    709 			if (edid_mon->det_mon[i].type >= DS_VENDOR && j == -1)
    710 				j = i;
    711 			if (edid_mon->det_mon[i].type == DS_RANGES) {
    712 				j = i;
    713 				break;
    714 			}
    715 		}
    716 		if (j != -1) {
    717 			struct monitor_ranges	*ranges =
    718 				&edid_mon->det_mon[j].section.ranges;
    719 			edid_mon->det_mon[j].type = DS_RANGES;
    720 			ranges->min_v = 0;
    721 			ranges->max_v = 200;
    722 			ranges->min_h = 0;
    723 			ranges->max_h = 200;
    724 		}
    725 		return 0;
    726 	}
    727 	/*
    728 	 * If there is no EDID, we will construct a bogus EDID for LVDS output
    729 	 * device. This is similar to what we have done in i830_lvds.c
    730 	 */
    731 	edid_mon = NULL;
    732 	edid_mon = xcalloc(1, sizeof(xf86Monitor));
    733 	if (!edid_mon) {
    734 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    735 			"Can't allocate memory for edid_mon.\n");
    736 		return 0;
    737 	}
    738 	/* Find the fixed panel mode.
    739 	 * In theory when there is no EDID, KMS kernel will return only one
    740 	 * mode. And this can be regarded as fixed lvds panel mode.
    741 	 * But it will be better to traverse the mode list to get the fixed
    742 	 * lvds panel mode again as we don't know whether some new modes
    743 	 * are added for the LVDS output device
    744 	 */
    745 	j = 0;
    746 	for (i = 0; i < koutput->count_modes; i++) {
    747 		mode_ptr = &koutput->modes[i];
    748 		if ((mode_ptr->hdisplay == p_lvds->hdisplay) &&
    749 			(mode_ptr->vdisplay == p_lvds->vdisplay)) {
    750 			/* find the fixed panel mode */
    751 			j = i;
    752 			break;
    753 		}
    754 	}
    755 	pmode = xnfalloc(sizeof(DisplayModeRec));
    756 	drmmode_ConvertFromKMode(output->scrn, &koutput->modes[j], pmode);
    757 	/*support DPM, instead of DPMS*/
    758 	edid_mon->features.dpms |= 0x1;
    759 	/*defaultly support RGB color display*/
    760 	edid_mon->features.display_type |= 0x1;
    761 	/*defaultly display support continuous-freqencey*/
    762 	edid_mon->features.msc |= 0x1;
    763 	/*defaultly  the EDID version is 1.4 */
    764 	edid_mon->ver.version = 1;
    765 	edid_mon->ver.revision = 4;
    766 	det_mon = edid_mon->det_mon;
    767 	if (pmode) {
    768 		/* now we construct new EDID monitor,
    769 		 * so filled one detailed timing block
    770 		 */
    771 		fill_detailed_lvds_block(det_mon, pmode);
    772 		/* the filed timing block should be set preferred*/
    773 		edid_mon->features.msc |= 0x2;
    774 		det_mon = det_mon + 1;
    775 	}
    776 	/* Set wide sync ranges so we get all modes
    777 	 * handed to valid_mode for checking
    778 	 */
    779 	det_mon->type = DS_RANGES;
    780 	det_mon->section.ranges.min_v = 0;
    781 	det_mon->section.ranges.max_v = 200;
    782 	det_mon->section.ranges.min_h = 0;
    783 	det_mon->section.ranges.max_h = 200;
    784 	output->MonInfo = edid_mon;
    785 	return 0;
    786 }
    787 
    788 static DisplayModePtr
    789 drmmode_output_get_modes(xf86OutputPtr output)
    790 {
    791 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    792 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    793 	drmmode_ptr drmmode = drmmode_output->drmmode;
    794 	int i;
    795 	DisplayModePtr Modes = NULL, Mode;
    796 	drmModePropertyPtr props;
    797 	struct fixed_panel_lvds *p_lvds;
    798 	drmModeModeInfo *mode_ptr;
    799 
    800 	/* look for an EDID property */
    801 	for (i = 0; i < koutput->count_props; i++) {
    802 		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
    803 		if (!props)
    804 			continue;
    805 		if (!(props->flags & DRM_MODE_PROP_BLOB)) {
    806 			drmModeFreeProperty(props);
    807 			continue;
    808 		}
    809 
    810 		if (!strcmp(props->name, "EDID")) {
    811 			drmModeFreePropertyBlob(drmmode_output->edid_blob);
    812 			drmmode_output->edid_blob =
    813 				drmModeGetPropertyBlob(drmmode->fd,
    814 						       koutput->prop_values[i]);
    815 		}
    816 		drmModeFreeProperty(props);
    817 	}
    818 
    819 	if (drmmode_output->edid_blob)
    820 		xf86OutputSetEDID(output,
    821 				  xf86InterpretEDID(output->scrn->scrnIndex,
    822 						    drmmode_output->edid_blob->data));
    823 	else
    824 		xf86OutputSetEDID(output,
    825 				  xf86InterpretEDID(output->scrn->scrnIndex,
    826 						    NULL));
    827 
    828 	/* modes should already be available */
    829 	for (i = 0; i < koutput->count_modes; i++) {
    830 		Mode = xnfalloc(sizeof(DisplayModeRec));
    831 
    832 		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
    833 					 Mode);
    834 		Modes = xf86ModesAdd(Modes, Mode);
    835 
    836 	}
    837 	p_lvds = drmmode_output->private_data;
    838 	/*
    839 	 * If the connector type is LVDS, we will traverse the kernel mode to
    840 	 * get the panel limit.
    841 	 * If it is incorrect, please fix me.
    842 	 */
    843 	if ((koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) && p_lvds) {
    844 		p_lvds->hdisplay = 0;
    845 		p_lvds->vdisplay = 0;
    846 		for (i = 0; i < koutput->count_modes; i++) {
    847 			mode_ptr = &koutput->modes[i];
    848 			if ((mode_ptr->hdisplay >= p_lvds->hdisplay) &&
    849 				(mode_ptr->vdisplay >= p_lvds->vdisplay)) {
    850 				p_lvds->hdisplay = mode_ptr->hdisplay;
    851 				p_lvds->vdisplay = mode_ptr->vdisplay;
    852 			}
    853 		}
    854 		if (!p_lvds->hdisplay || !p_lvds->vdisplay)
    855 			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    856 				"Incorrect KMS mode.\n");
    857 		drmmode_output_lvds_edid(output, p_lvds);
    858 	}
    859 	return Modes;
    860 }
    861 
    862 static void
    863 drmmode_output_destroy(xf86OutputPtr output)
    864 {
    865 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    866 	int i;
    867 
    868 	if (drmmode_output->edid_blob)
    869 		drmModeFreePropertyBlob(drmmode_output->edid_blob);
    870 	for (i = 0; i < drmmode_output->num_props; i++) {
    871 	    drmModeFreeProperty(drmmode_output->props[i].mode_prop);
    872 	    xfree(drmmode_output->props[i].atoms);
    873 	}
    874 	xfree(drmmode_output->props);
    875 	drmModeFreeConnector(drmmode_output->mode_output);
    876 	if (drmmode_output->private_data) {
    877 		xfree(drmmode_output->private_data);
    878 		drmmode_output->private_data = NULL;
    879 	}
    880 	if (drmmode_output->backlight_iface)
    881 		drmmode_backlight_set(output, drmmode_output->backlight_active_level);
    882 	xfree(drmmode_output);
    883 	output->driver_private = NULL;
    884 }
    885 
    886 static void
    887 drmmode_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode)
    888 {
    889 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    890 
    891 	if (!drmmode_output->backlight_iface)
    892 		return;
    893 
    894 	if (mode == DPMSModeOn) {
    895 		/* If we're going from off->on we may need to turn on the backlight. */
    896 		if (oldmode != DPMSModeOn)
    897 			drmmode_backlight_set(output, drmmode_output->backlight_active_level);
    898 	} else {
    899 		/* Only save the current backlight value if we're going from on to off. */
    900 		if (oldmode == DPMSModeOn)
    901 			drmmode_output->backlight_active_level = drmmode_backlight_get(output);
    902 		drmmode_backlight_set(output, 0);
    903 	}
    904 }
    905 
    906 static void
    907 drmmode_output_dpms(xf86OutputPtr output, int mode)
    908 {
    909 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    910 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    911 	drmmode_ptr drmmode = drmmode_output->drmmode;
    912 	int i;
    913 	drmModePropertyPtr props;
    914 
    915 	for (i = 0; i < koutput->count_props; i++) {
    916 		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
    917 		if (!props)
    918 			continue;
    919 
    920 		if (!strcmp(props->name, "DPMS")) {
    921                         drmModeConnectorSetProperty(drmmode->fd,
    922                                 drmmode_output->output_id,
    923                                 props->prop_id,
    924                                 mode);
    925 			drmmode_output_dpms_backlight(output,
    926 				drmmode_output->dpms_mode,
    927 				mode);
    928 			drmmode_output->dpms_mode = mode;
    929                         drmModeFreeProperty(props);
    930                         return;
    931 		}
    932 		drmModeFreeProperty(props);
    933 	}
    934 }
    935 
    936 int
    937 drmmode_output_dpms_status(xf86OutputPtr output)
    938 {
    939 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    940 
    941 	return drmmode_output->dpms_mode;
    942 }
    943 
    944 static Bool
    945 drmmode_property_ignore(drmModePropertyPtr prop)
    946 {
    947     if (!prop)
    948 	return TRUE;
    949     /* ignore blob prop */
    950     if (prop->flags & DRM_MODE_PROP_BLOB)
    951 	return TRUE;
    952     /* ignore standard property */
    953     if (!strcmp(prop->name, "EDID") ||
    954 	    !strcmp(prop->name, "DPMS"))
    955 	return TRUE;
    956 
    957     return FALSE;
    958 }
    959 
    960 #define BACKLIGHT_NAME             "Backlight"
    961 #define BACKLIGHT_DEPRECATED_NAME  "BACKLIGHT"
    962 static Atom backlight_atom, backlight_deprecated_atom;
    963 
    964 static void
    965 drmmode_output_create_resources(xf86OutputPtr output)
    966 {
    967     drmmode_output_private_ptr drmmode_output = output->driver_private;
    968     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
    969     drmmode_ptr drmmode = drmmode_output->drmmode;
    970     drmModePropertyPtr drmmode_prop;
    971     int i, j, err;
    972 
    973     drmmode_output->props = xcalloc(mode_output->count_props, sizeof(drmmode_prop_rec));
    974     if (!drmmode_output->props)
    975 	return;
    976 
    977     drmmode_output->num_props = 0;
    978     for (i = 0, j = 0; i < mode_output->count_props; i++) {
    979 	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
    980 	if (drmmode_property_ignore(drmmode_prop)) {
    981 	    drmModeFreeProperty(drmmode_prop);
    982 	    continue;
    983 	}
    984 	drmmode_output->props[j].mode_prop = drmmode_prop;
    985 	drmmode_output->props[j].value = mode_output->prop_values[i];
    986 	drmmode_output->num_props++;
    987 	j++;
    988     }
    989 
    990     for (i = 0; i < drmmode_output->num_props; i++) {
    991 	drmmode_prop_ptr p = &drmmode_output->props[i];
    992 	drmmode_prop = p->mode_prop;
    993 
    994 	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
    995 	    INT32 range[2];
    996 
    997 	    p->num_atoms = 1;
    998 	    p->atoms = xcalloc(p->num_atoms, sizeof(Atom));
    999 	    if (!p->atoms)
   1000 		continue;
   1001 	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
   1002 	    range[0] = drmmode_prop->values[0];
   1003 	    range[1] = drmmode_prop->values[1];
   1004 	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
   1005 		    FALSE, TRUE,
   1006 		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
   1007 		    2, range);
   1008 	    if (err != 0) {
   1009 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1010 			"RRConfigureOutputProperty error, %d\n", err);
   1011 	    }
   1012 	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   1013 		    XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE);
   1014 	    if (err != 0) {
   1015 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1016 			"RRChangeOutputProperty error, %d\n", err);
   1017 	    }
   1018 	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
   1019 	    p->num_atoms = drmmode_prop->count_enums + 1;
   1020 	    p->atoms = xcalloc(p->num_atoms, sizeof(Atom));
   1021 	    if (!p->atoms)
   1022 		continue;
   1023 	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
   1024 	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
   1025 		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
   1026 		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
   1027 	    }
   1028 	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
   1029 		    FALSE, FALSE,
   1030 		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
   1031 		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
   1032 	    if (err != 0) {
   1033 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1034 			"RRConfigureOutputProperty error, %d\n", err);
   1035 	    }
   1036 	    for (j = 0; j < drmmode_prop->count_enums; j++)
   1037 		if (drmmode_prop->enums[j].value == p->value)
   1038 		    break;
   1039 	    /* there's always a matching value */
   1040 	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   1041 		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
   1042 	    if (err != 0) {
   1043 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1044 			"RRChangeOutputProperty error, %d\n", err);
   1045 	    }
   1046 	}
   1047     }
   1048 
   1049     if (drmmode_output->backlight_iface) {
   1050 	INT32 data, backlight_range[2];
   1051 	/* Set up the backlight property, which takes effect immediately
   1052 	 * and accepts values only within the backlight_range. */
   1053 	backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, TRUE);
   1054 	backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME,
   1055 		sizeof(BACKLIGHT_DEPRECATED_NAME) - 1, TRUE);
   1056 
   1057 	backlight_range[0] = 0;
   1058 	backlight_range[1] = drmmode_output->backlight_max;
   1059 	err = RRConfigureOutputProperty(output->randr_output, backlight_atom,
   1060 	                                FALSE, TRUE, FALSE, 2, backlight_range);
   1061 	if (err != 0) {
   1062 	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1063 	               "RRConfigureOutputProperty error, %d\n", err);
   1064 	}
   1065 	err = RRConfigureOutputProperty(output->randr_output, backlight_deprecated_atom,
   1066 	                                FALSE, TRUE, FALSE, 2, backlight_range);
   1067 	if (err != 0) {
   1068 	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1069 	               "RRConfigureOutputProperty error, %d\n", err);
   1070 	}
   1071 	/* Set the current value of the backlight property */
   1072 	data = drmmode_output->backlight_active_level;
   1073 	err = RRChangeOutputProperty(output->randr_output, backlight_atom,
   1074 	                             XA_INTEGER, 32, PropModeReplace, 1, &data,
   1075 	                             FALSE, TRUE);
   1076 	if (err != 0) {
   1077 	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1078 	               "RRChangeOutputProperty error, %d\n", err);
   1079 	}
   1080 	err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom,
   1081 	                             XA_INTEGER, 32, PropModeReplace, 1, &data,
   1082 	                             FALSE, TRUE);
   1083 	if (err != 0) {
   1084 	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1085 	               "RRChangeOutputProperty error, %d\n", err);
   1086 	}
   1087     }
   1088 }
   1089 
   1090 static Bool
   1091 drmmode_output_set_property(xf86OutputPtr output, Atom property,
   1092 		RRPropertyValuePtr value)
   1093 {
   1094     drmmode_output_private_ptr drmmode_output = output->driver_private;
   1095     drmmode_ptr drmmode = drmmode_output->drmmode;
   1096     int i;
   1097 
   1098     if (property == backlight_atom || property == backlight_deprecated_atom) {
   1099 	INT32 val;
   1100 
   1101 	if (value->type != XA_INTEGER || value->format != 32 ||
   1102 	    value->size != 1)
   1103 	{
   1104 	    return FALSE;
   1105 	}
   1106 
   1107 	val = *(INT32 *)value->data;
   1108 	if (val < 0 || val > drmmode_output->backlight_max)
   1109 	    return FALSE;
   1110 
   1111 	if (drmmode_output->dpms_mode == DPMSModeOn)
   1112 	    drmmode_backlight_set(output, val);
   1113 	drmmode_output->backlight_active_level = val;
   1114 	return TRUE;
   1115     }
   1116 
   1117     for (i = 0; i < drmmode_output->num_props; i++) {
   1118 	drmmode_prop_ptr p = &drmmode_output->props[i];
   1119 
   1120 	if (p->atoms[0] != property)
   1121 	    continue;
   1122 
   1123 	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
   1124 	    uint32_t val;
   1125 
   1126 	    if (value->type != XA_INTEGER || value->format != 32 ||
   1127 		    value->size != 1)
   1128 		return FALSE;
   1129 	    val = *(uint32_t *)value->data;
   1130 
   1131 	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
   1132 		    p->mode_prop->prop_id, (uint64_t)val);
   1133 	    return TRUE;
   1134 	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
   1135 	    Atom	atom;
   1136 	    const char	*name;
   1137 	    int		j;
   1138 
   1139 	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
   1140 		return FALSE;
   1141 	    memcpy(&atom, value->data, 4);
   1142 	    name = NameForAtom(atom);
   1143 
   1144 	    /* search for matching name string, then set its value down */
   1145 	    for (j = 0; j < p->mode_prop->count_enums; j++) {
   1146 		if (!strcmp(p->mode_prop->enums[j].name, name)) {
   1147 		    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
   1148 			    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
   1149 		    return TRUE;
   1150 		}
   1151 	    }
   1152 	}
   1153     }
   1154 
   1155     return TRUE;
   1156 }
   1157 
   1158 static Bool
   1159 drmmode_output_get_property(xf86OutputPtr output, Atom property)
   1160 {
   1161     drmmode_output_private_ptr drmmode_output = output->driver_private;
   1162     int err;
   1163 
   1164     if (property == backlight_atom || property == backlight_deprecated_atom) {
   1165 	INT32 val;
   1166 
   1167 	if (! drmmode_output->backlight_iface)
   1168 	    return FALSE;
   1169 
   1170 	val = drmmode_backlight_get(output);
   1171 	if (val < 0)
   1172 	    return FALSE;
   1173 	err = RRChangeOutputProperty(output->randr_output, property,
   1174 	                             XA_INTEGER, 32, PropModeReplace, 1, &val,
   1175 	                             FALSE, TRUE);
   1176 	if (err != 0) {
   1177 	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1178 	               "RRChangeOutputProperty error, %d\n", err);
   1179 	    return FALSE;
   1180 	}
   1181 
   1182 	return TRUE;
   1183     }
   1184 
   1185     return TRUE;
   1186 }
   1187 
   1188 static const xf86OutputFuncsRec drmmode_output_funcs = {
   1189 	.create_resources = drmmode_output_create_resources,
   1190 #ifdef RANDR_12_INTERFACE
   1191 	.set_property = drmmode_output_set_property,
   1192 	.get_property = drmmode_output_get_property,
   1193 #endif
   1194 	.dpms = drmmode_output_dpms,
   1195 #if 0
   1196 
   1197 	.save = drmmode_crt_save,
   1198 	.restore = drmmode_crt_restore,
   1199 	.mode_fixup = drmmode_crt_mode_fixup,
   1200 	.prepare = drmmode_output_prepare,
   1201 	.mode_set = drmmode_crt_mode_set,
   1202 	.commit = drmmode_output_commit,
   1203 #endif
   1204 	.detect = drmmode_output_detect,
   1205 	.mode_valid = drmmode_output_mode_valid,
   1206 
   1207 	.get_modes = drmmode_output_get_modes,
   1208 	.destroy = drmmode_output_destroy
   1209 };
   1210 
   1211 static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
   1212 				      SubPixelHorizontalRGB,
   1213 				      SubPixelHorizontalBGR,
   1214 				      SubPixelVerticalRGB,
   1215 				      SubPixelVerticalBGR,
   1216 				      SubPixelNone };
   1217 
   1218 static const char *output_names[] = { "None",
   1219 				      "VGA",
   1220 				      "DVI",
   1221 				      "DVI",
   1222 				      "DVI",
   1223 				      "Composite",
   1224 				      "TV",
   1225 				      "LVDS",
   1226 				      "CTV",
   1227 				      "DIN",
   1228 				      "DP",
   1229 				      "HDMI",
   1230 				      "HDMI",
   1231 };
   1232 
   1233 
   1234 static void
   1235 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
   1236 {
   1237 	xf86OutputPtr output;
   1238 	drmModeConnectorPtr koutput;
   1239 	drmModeEncoderPtr kencoder;
   1240 	drmmode_output_private_ptr drmmode_output;
   1241 	char name[32];
   1242 
   1243 	koutput = drmModeGetConnector(drmmode->fd,
   1244 				      drmmode->mode_res->connectors[num]);
   1245 	if (!koutput)
   1246 		return;
   1247 
   1248 	kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
   1249 	if (!kencoder) {
   1250 		drmModeFreeConnector(koutput);
   1251 		return;
   1252 	}
   1253 
   1254 	snprintf(name, 32, "%s%d", output_names[koutput->connector_type],
   1255 		 koutput->connector_type_id);
   1256 
   1257 	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
   1258 	if (!output) {
   1259 		drmModeFreeEncoder(kencoder);
   1260 		drmModeFreeConnector(koutput);
   1261 		return;
   1262 	}
   1263 
   1264 	drmmode_output = xcalloc(sizeof(drmmode_output_private_rec), 1);
   1265 	if (!drmmode_output) {
   1266 		xf86OutputDestroy(output);
   1267 		drmModeFreeConnector(koutput);
   1268 		drmModeFreeEncoder(kencoder);
   1269 		return;
   1270 	}
   1271 	/*
   1272 	 * If the connector type of the output device is LVDS, we will
   1273 	 * allocate the private_data to store the panel limit.
   1274 	 * For example: hdisplay, vdisplay
   1275 	 */
   1276 	drmmode_output->private_data = NULL;
   1277 	if (koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS) {
   1278 		drmmode_output->private_data = xcalloc(
   1279 				sizeof(struct fixed_panel_lvds), 1);
   1280 		if (!drmmode_output->private_data)
   1281 			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
   1282 				"Can't allocate private memory for LVDS.\n");
   1283 	}
   1284 	drmmode_output->output_id = drmmode->mode_res->connectors[num];
   1285 	drmmode_output->mode_output = koutput;
   1286 	drmmode_output->mode_encoder = kencoder;
   1287 	drmmode_output->drmmode = drmmode;
   1288 	output->mm_width = koutput->mmWidth;
   1289 	output->mm_height = koutput->mmHeight;
   1290 
   1291 	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
   1292 	output->driver_private = drmmode_output;
   1293 
   1294 	if (koutput->connector_type ==  DRM_MODE_CONNECTOR_LVDS)
   1295 		drmmode_backlight_init(output);
   1296 
   1297 	output->possible_crtcs = kencoder->possible_crtcs;
   1298 	output->possible_clones = kencoder->possible_clones;
   1299 	return;
   1300 }
   1301 
   1302 static Bool
   1303 drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
   1304 {
   1305 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   1306 	drmmode_crtc_private_ptr
   1307 		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
   1308 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1309 	I830Ptr     pI830 = I830PTR(scrn);
   1310 	i830_memory *old_front = NULL;
   1311 	Bool	    tiled, ret;
   1312 	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
   1313 	uint32_t    old_fb_id;
   1314 	int	    i, pitch, old_width, old_height, old_pitch;
   1315 
   1316 	if (scrn->virtualX == width && scrn->virtualY == height)
   1317 		return TRUE;
   1318 
   1319 	pitch = i830_pad_drawable_width(width, pI830->cpp);
   1320 	tiled = i830_tiled_width(pI830, &pitch, pI830->cpp);
   1321 	xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1322 		   "Allocate new frame buffer %dx%d stride %d\n",
   1323 		   width, height, pitch);
   1324 
   1325 	old_width = scrn->virtualX;
   1326 	old_height = scrn->virtualY;
   1327 	old_pitch = scrn->displayWidth;
   1328 	old_fb_id = drmmode->fb_id;
   1329 	old_front = pI830->front_buffer;
   1330 
   1331 	scrn->virtualX = width;
   1332 	scrn->virtualY = height;
   1333 	scrn->displayWidth = pitch;
   1334 	pI830->front_buffer = i830_allocate_framebuffer(scrn);
   1335 	if (!pI830->front_buffer)
   1336 		goto fail;
   1337 
   1338 	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
   1339 			   scrn->bitsPerPixel, pitch * pI830->cpp,
   1340 			   pI830->front_buffer->bo->handle,
   1341 			   &drmmode->fb_id);
   1342 	if (ret)
   1343 		goto fail;
   1344 
   1345 	i830_set_pixmap_bo(screen->GetScreenPixmap(screen), pI830->front_buffer->bo);
   1346 
   1347 	screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen),
   1348 				   width, height, -1, -1, pitch * pI830->cpp, NULL);
   1349 
   1350 	for (i = 0; i < xf86_config->num_crtc; i++) {
   1351 		xf86CrtcPtr crtc = xf86_config->crtc[i];
   1352 
   1353 		if (!crtc->enabled)
   1354 			continue;
   1355 
   1356 		drmmode_set_mode_major(crtc, &crtc->mode,
   1357 				       crtc->rotation, crtc->x, crtc->y);
   1358 	}
   1359 
   1360 	if (old_fb_id)
   1361 		drmModeRmFB(drmmode->fd, old_fb_id);
   1362 	if (old_front)
   1363 		i830_free_memory(scrn, old_front);
   1364 
   1365 	return TRUE;
   1366 
   1367  fail:
   1368 	if (pI830->front_buffer)
   1369 		i830_free_memory(scrn, pI830->front_buffer);
   1370 	pI830->front_buffer = old_front;
   1371 	scrn->virtualX = old_width;
   1372 	scrn->virtualY = old_height;
   1373 	scrn->displayWidth = old_pitch;
   1374 	drmmode->fb_id = old_fb_id;
   1375 
   1376 	return FALSE;
   1377 }
   1378 
   1379 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
   1380 	drmmode_xf86crtc_resize
   1381 };
   1382 
   1383 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
   1384 {
   1385 	xf86CrtcConfigPtr   xf86_config;
   1386 	drmmode_ptr drmmode;
   1387 	int i;
   1388 
   1389 	drmmode = xnfalloc(sizeof *drmmode);
   1390 	drmmode->fd = fd;
   1391 	drmmode->fb_id = 0;
   1392 
   1393 	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
   1394 	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   1395 
   1396 	drmmode->cpp = cpp;
   1397 	drmmode->mode_res = drmModeGetResources(drmmode->fd);
   1398 	if (!drmmode->mode_res) {
   1399 		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
   1400 			   "failed to get resources: %s\n", strerror(errno));
   1401 		return FALSE;
   1402 	}
   1403 
   1404 	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
   1405 			     drmmode->mode_res->max_height);
   1406 	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
   1407 		drmmode_crtc_init(pScrn, drmmode, i);
   1408 
   1409 	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
   1410 		drmmode_output_init(pScrn, drmmode, i);
   1411 
   1412 	xf86InitialConfiguration(pScrn, TRUE);
   1413 
   1414 	return TRUE;
   1415 }
   1416 
   1417 int
   1418 drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc)
   1419 {
   1420 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1421 
   1422 	return drm_intel_get_pipe_from_crtc_id (bufmgr, drmmode_crtc->mode_crtc->crtc_id);
   1423 }
   1424 
   1425 void drmmode_closefb(ScrnInfoPtr scrn)
   1426 {
   1427 	xf86CrtcConfigPtr xf86_config;
   1428 	drmmode_crtc_private_ptr drmmode_crtc;
   1429 	drmmode_ptr drmmode;
   1430 
   1431 	xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   1432 
   1433 	drmmode_crtc = xf86_config->crtc[0]->driver_private;
   1434 	drmmode = drmmode_crtc->drmmode;
   1435 
   1436 	drmModeRmFB(drmmode->fd, drmmode->fb_id);
   1437 	drmmode->fb_id = 0;
   1438 }
   1439