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