drmmode_display.c revision 53ba5c8b
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@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
46typedef struct {
47    int fd;
48    uint32_t fb_id;
49    drmModeResPtr mode_res;
50    int cpp;
51} drmmode_rec, *drmmode_ptr;
52
53typedef 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
61typedef 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
68struct fixed_panel_lvds {
69	int hdisplay;
70	int vdisplay;
71};
72typedef 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
87static void
88drmmode_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 */
95static 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
114static void
115drmmode_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
145static int
146drmmode_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
180static int
181drmmode_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
210static void
211drmmode_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
233static void
234drmmode_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
265static void
266drmmode_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
292static void
293drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
294{
295
296}
297
298static Bool
299drmmode_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);
403done:
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
413static void
414drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
415{
416
417}
418
419static void
420drmmode_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
428static void
429drmmode_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
444static void
445drmmode_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
454static void
455drmmode_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
464static void *
465drmmode_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
500static PixmapPtr
501drmmode_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
539static void
540drmmode_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
561static void
562drmmode_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
572static 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
588static void
589drmmode_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
607void
608drmmode_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
614static xf86OutputStatus
615drmmode_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
641static Bool
642drmmode_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
662static 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
685static 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
788static DisplayModePtr
789drmmode_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
862static void
863drmmode_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
886static void
887drmmode_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
906static void
907drmmode_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
936int
937drmmode_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
944static Bool
945drmmode_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"
962static Atom backlight_atom, backlight_deprecated_atom;
963
964static void
965drmmode_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
1090static Bool
1091drmmode_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
1158static Bool
1159drmmode_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
1188static 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
1211static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1212				      SubPixelHorizontalRGB,
1213				      SubPixelHorizontalBGR,
1214				      SubPixelVerticalRGB,
1215				      SubPixelVerticalBGR,
1216				      SubPixelNone };
1217
1218static 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
1234static void
1235drmmode_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
1302static Bool
1303drmmode_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
1379static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1380	drmmode_xf86crtc_resize
1381};
1382
1383Bool 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
1417int
1418drmmode_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
1425void 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