1706f2543Smrg/*
2706f2543Smrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
24706f2543Smrg#include <xorg-config.h>
25706f2543Smrg#else
26706f2543Smrg#ifdef HAVE_CONFIG_H
27706f2543Smrg#include <config.h>
28706f2543Smrg#endif
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include "xf86.h"
32706f2543Smrg#include "os.h"
33706f2543Smrg#include "globals.h"
34706f2543Smrg#include "xf86.h"
35706f2543Smrg#include "xf86Modes.h"
36706f2543Smrg#include "xf86Priv.h"
37706f2543Smrg#include "xf86DDC.h"
38706f2543Smrg#include "mipointer.h"
39706f2543Smrg#include "windowstr.h"
40706f2543Smrg#include "inputstr.h"
41706f2543Smrg#include <randrstr.h>
42706f2543Smrg#include <X11/extensions/render.h>
43706f2543Smrg
44706f2543Smrg#include "xf86Crtc.h"
45706f2543Smrg#include "xf86RandR12.h"
46706f2543Smrg
47706f2543Smrgtypedef struct _xf86RandR12Info {
48706f2543Smrg    int				    virtualX;
49706f2543Smrg    int				    virtualY;
50706f2543Smrg    int				    mmWidth;
51706f2543Smrg    int				    mmHeight;
52706f2543Smrg    int				    maxX;
53706f2543Smrg    int				    maxY;
54706f2543Smrg    int				    pointerX;
55706f2543Smrg    int				    pointerY;
56706f2543Smrg    Rotation			    rotation; /* current mode */
57706f2543Smrg    Rotation                        supported_rotations; /* driver supported */
58706f2543Smrg
59706f2543Smrg    /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends
60706f2543Smrg     * (actually, any time that we switch back into our VT).
61706f2543Smrg     *
62706f2543Smrg     * See https://bugs.freedesktop.org/show_bug.cgi?id=21554
63706f2543Smrg     */
64706f2543Smrg    xf86EnterVTProc *orig_EnterVT;
65706f2543Smrg} XF86RandRInfoRec, *XF86RandRInfoPtr;
66706f2543Smrg
67706f2543Smrg#ifdef RANDR_12_INTERFACE
68706f2543Smrgstatic Bool xf86RandR12Init12 (ScreenPtr pScreen);
69706f2543Smrgstatic Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen);
70706f2543Smrg#endif
71706f2543Smrg
72706f2543Smrgstatic int xf86RandR12Generation;
73706f2543Smrg
74706f2543Smrgstatic DevPrivateKeyRec xf86RandR12KeyRec;
75706f2543Smrgstatic DevPrivateKey xf86RandR12Key;
76706f2543Smrg#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \
77706f2543Smrg    dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key))
78706f2543Smrg
79706f2543Smrg
80706f2543Smrgstatic int
81706f2543Smrgxf86RandR12ModeRefresh (DisplayModePtr mode)
82706f2543Smrg{
83706f2543Smrg    if (mode->VRefresh)
84706f2543Smrg	return (int) (mode->VRefresh + 0.5);
85706f2543Smrg    else
86706f2543Smrg	return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
87706f2543Smrg}
88706f2543Smrg
89706f2543Smrg/* Adapt panning area; return TRUE if panning area was valid without adaption */
90706f2543Smrgstatic int
91706f2543Smrgxf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight)
92706f2543Smrg{
93706f2543Smrg    int ret = TRUE;
94706f2543Smrg
95706f2543Smrg    if (crtc->version < 2)
96706f2543Smrg	return FALSE;
97706f2543Smrg
98706f2543Smrg    if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) {
99706f2543Smrg	/* Panning in X is disabled */
100706f2543Smrg	if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2)
101706f2543Smrg	    /* Illegal configuration -> fail/disable */
102706f2543Smrg	    ret = FALSE;
103706f2543Smrg	crtc->panningTotalArea.x1    = crtc->panningTotalArea.x2    = 0;
104706f2543Smrg	crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0;
105706f2543Smrg	crtc->panningBorder[0]       = crtc->panningBorder[2]       = 0;
106706f2543Smrg    } else {
107706f2543Smrg	/* Panning in X is enabled */
108706f2543Smrg	if (crtc->panningTotalArea.x1 < 0) {
109706f2543Smrg	    /* Panning region outside screen -> move inside */
110706f2543Smrg	    crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1;
111706f2543Smrg	    crtc->panningTotalArea.x1 = 0;
112706f2543Smrg	    ret = FALSE;
113706f2543Smrg	}
114706f2543Smrg	if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) {
115706f2543Smrg	    /* Panning region smaller than displayed area -> crop to displayed area */
116706f2543Smrg	    crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay;
117706f2543Smrg	    ret = FALSE;
118706f2543Smrg	}
119706f2543Smrg	if (crtc->panningTotalArea.x2 > screenWidth) {
120706f2543Smrg	    /* Panning region larger than screen -> move inside, then crop to screen */
121706f2543Smrg	    crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth;
122706f2543Smrg	    crtc->panningTotalArea.x2 = screenWidth;
123706f2543Smrg	    ret = FALSE;
124706f2543Smrg	    if (crtc->panningTotalArea.x1 < 0)
125706f2543Smrg		crtc->panningTotalArea.x1 = 0;
126706f2543Smrg	}
127706f2543Smrg	if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) {
128706f2543Smrg	    /* Borders too large -> set to 0 */
129706f2543Smrg	    crtc->panningBorder[0] = crtc->panningBorder[2] = 0;
130706f2543Smrg	    ret = FALSE;
131706f2543Smrg	}
132706f2543Smrg    }
133706f2543Smrg
134706f2543Smrg    if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) {
135706f2543Smrg	/* Panning in Y is disabled */
136706f2543Smrg	if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2)
137706f2543Smrg	    /* Illegal configuration -> fail/disable */
138706f2543Smrg	    ret = FALSE;
139706f2543Smrg	crtc->panningTotalArea.y1    = crtc->panningTotalArea.y2    = 0;
140706f2543Smrg	crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0;
141706f2543Smrg	crtc->panningBorder[1]       = crtc->panningBorder[3]       = 0;
142706f2543Smrg    } else {
143706f2543Smrg	/* Panning in Y is enabled */
144706f2543Smrg	if (crtc->panningTotalArea.y1 < 0) {
145706f2543Smrg	    /* Panning region outside screen -> move inside */
146706f2543Smrg	    crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1;
147706f2543Smrg	    crtc->panningTotalArea.y1 = 0;
148706f2543Smrg	    ret = FALSE;
149706f2543Smrg	}
150706f2543Smrg	if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) {
151706f2543Smrg	    /* Panning region smaller than displayed area -> crop to displayed area */
152706f2543Smrg	    crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay;
153706f2543Smrg	    ret = FALSE;
154706f2543Smrg	}
155706f2543Smrg	if (crtc->panningTotalArea.y2 > screenHeight) {
156706f2543Smrg	    /* Panning region larger than screen -> move inside, then crop to screen */
157706f2543Smrg	    crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight;
158706f2543Smrg	    crtc->panningTotalArea.y2 = screenHeight;
159706f2543Smrg	    ret = FALSE;
160706f2543Smrg	    if (crtc->panningTotalArea.y1 < 0)
161706f2543Smrg		crtc->panningTotalArea.y1 = 0;
162706f2543Smrg	}
163706f2543Smrg	if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) {
164706f2543Smrg	    /* Borders too large -> set to 0 */
165706f2543Smrg	    crtc->panningBorder[1] = crtc->panningBorder[3] = 0;
166706f2543Smrg	    ret = FALSE;
167706f2543Smrg	}
168706f2543Smrg    }
169706f2543Smrg
170706f2543Smrg    return ret;
171706f2543Smrg}
172706f2543Smrg
173706f2543Smrg/*
174706f2543Smrg * The heart of the panning operation:
175706f2543Smrg *
176706f2543Smrg * Given a frame buffer position (fb_x, fb_y),
177706f2543Smrg * and a crtc position (crtc_x, crtc_y),
178706f2543Smrg * and a transform matrix which maps frame buffer to crtc,
179706f2543Smrg * compute a panning position (pan_x, pan_y) that
180706f2543Smrg * makes the resulting transform line those two up
181706f2543Smrg */
182706f2543Smrg
183706f2543Smrgstatic void
184706f2543Smrgxf86ComputeCrtcPan (Bool transform_in_use,
185706f2543Smrg		    struct pixman_f_transform *m,
186706f2543Smrg		    double screen_x, double screen_y,
187706f2543Smrg		    double crtc_x, double crtc_y,
188706f2543Smrg		    int old_pan_x, int old_pan_y,
189706f2543Smrg		    int *new_pan_x, int *new_pan_y)
190706f2543Smrg{
191706f2543Smrg    if (transform_in_use) {
192706f2543Smrg	/*
193706f2543Smrg	 * Given the current transform, M, the current position
194706f2543Smrg	 * on the Screen, S, and the desired position on the CRTC,
195706f2543Smrg	 * C, compute a translation, T, such that:
196706f2543Smrg	 *
197706f2543Smrg	 * M T S = C
198706f2543Smrg	 *
199706f2543Smrg	 * where T is of the form
200706f2543Smrg	 *
201706f2543Smrg	 * | 1 0 dx |
202706f2543Smrg	 * | 0 1 dy |
203706f2543Smrg	 * | 0 0 1  |
204706f2543Smrg	 *
205706f2543Smrg	 * M T S =
206706f2543Smrg	 *   | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 |   | Cx F |
207706f2543Smrg	 *   | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F |
208706f2543Smrg	 *   | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 |   |  F   |
209706f2543Smrg	 *
210706f2543Smrg	 * R = M S
211706f2543Smrg	 *
212706f2543Smrg	 *   Cx F = M00 dx + M01 dy + R0
213706f2543Smrg	 *   Cy F = M10 dx + M11 dy + R1
214706f2543Smrg	 *      F = M20 dx + M21 dy + R2
215706f2543Smrg	 *
216706f2543Smrg	 * Zero out dx, then dy
217706f2543Smrg	 *
218706f2543Smrg	 * F (Cx M10 - Cy M00) =
219706f2543Smrg	 *	    (M10 M01 - M00 M11) dy + M10 R0 - M00 R1
220706f2543Smrg	 * F (M10 - Cy M20) =
221706f2543Smrg	 *	    (M10 M21 - M20 M11) dy + M10 R2 - M20 R1
222706f2543Smrg	 *
223706f2543Smrg	 * F (Cx M11 - Cy M01) =
224706f2543Smrg	 *	    (M11 M00 - M01 M10) dx + M11 R0 - M01 R1
225706f2543Smrg	 * F (M11 - Cy M21) =
226706f2543Smrg	 *	    (M11 M20 - M21 M10) dx + M11 R2 - M21 R1
227706f2543Smrg	 *
228706f2543Smrg	 * Make some temporaries
229706f2543Smrg	 *
230706f2543Smrg	 * T = | Cx M10 - Cy M00 |
231706f2543Smrg	 *     | Cx M11 - Cy M01 |
232706f2543Smrg	 *
233706f2543Smrg	 * U = | M10 M01 - M00 M11 |
234706f2543Smrg	 *     | M11 M00 - M01 M10 |
235706f2543Smrg	 *
236706f2543Smrg	 * Q = | M10 R0 - M00 R1 |
237706f2543Smrg	 *     | M11 R0 - M01 R1 |
238706f2543Smrg	 *
239706f2543Smrg	 * P = | M10 - Cy M20 |
240706f2543Smrg	 *     | M11 - Cy M21 |
241706f2543Smrg	 *
242706f2543Smrg	 * W = | M10 M21 - M20 M11 |
243706f2543Smrg	 *     | M11 M20 - M21 M10 |
244706f2543Smrg	 *
245706f2543Smrg	 * V = | M10 R2 - M20 R1 |
246706f2543Smrg	 *	   | M11 R2 - M21 R1 |
247706f2543Smrg	 *
248706f2543Smrg	 * Rewrite:
249706f2543Smrg	 *
250706f2543Smrg	 * F T0 = U0 dy + Q0
251706f2543Smrg	 * F P0 = W0 dy + V0
252706f2543Smrg	 * F T1 = U1 dx + Q1
253706f2543Smrg	 * F P1 = W1 dx + V1
254706f2543Smrg	 *
255706f2543Smrg	 * Solve for F (two ways)
256706f2543Smrg	 *
257706f2543Smrg	 * F (W0 T0 - U0 P0)  = W0 Q0 - U0 V0
258706f2543Smrg	 *
259706f2543Smrg	 *     W0 Q0 - U0 V0
260706f2543Smrg	 * F = -------------
261706f2543Smrg	 *     W0 T0 - U0 P0
262706f2543Smrg	 *
263706f2543Smrg	 * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1
264706f2543Smrg	 *
265706f2543Smrg	 *     W1 Q1 - U1 V1
266706f2543Smrg	 * F = -------------
267706f2543Smrg	 *     W1 T1 - U1 P1
268706f2543Smrg	 *
269706f2543Smrg	 * We'll use which ever solution works (denominator != 0)
270706f2543Smrg	 *
271706f2543Smrg	 * Finally, solve for dx and dy:
272706f2543Smrg	 *
273706f2543Smrg	 * dx = (F T1 - Q1) / U1
274706f2543Smrg	 * dx = (F P1 - V1) / W1
275706f2543Smrg	 *
276706f2543Smrg	 * dy = (F T0 - Q0) / U0
277706f2543Smrg	 * dy = (F P0 - V0) / W0
278706f2543Smrg	 */
279706f2543Smrg	double			    r[3];
280706f2543Smrg	double			    q[2], u[2], t[2], v[2], w[2], p[2];
281706f2543Smrg	double			    f;
282706f2543Smrg	struct pict_f_vector	    d;
283706f2543Smrg	int			    i;
284706f2543Smrg
285706f2543Smrg	/* Get the un-normalized crtc coordinates again */
286706f2543Smrg	for (i = 0; i < 3; i++)
287706f2543Smrg	    r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2];
288706f2543Smrg
289706f2543Smrg	/* Combine values into temporaries */
290706f2543Smrg	for (i = 0; i < 2; i++) {
291706f2543Smrg	    q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1];
292706f2543Smrg	    u[i] = m->m[1][i] * m->m[0][1-i] - m->m[0][i] * m->m[1][1-i];
293706f2543Smrg	    t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y;
294706f2543Smrg
295706f2543Smrg	    v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1];
296706f2543Smrg	    w[i] = m->m[1][i] * m->m[2][1-i] - m->m[2][i] * m->m[1][1-i];
297706f2543Smrg	    p[i] = m->m[1][i] - m->m[2][i] * crtc_y;
298706f2543Smrg	}
299706f2543Smrg
300706f2543Smrg	/* Find a way to compute f */
301706f2543Smrg	f = 0;
302706f2543Smrg	for (i = 0; i < 2; i++) {
303706f2543Smrg	    double a = w[i] * q[i] - u[i] * v[i];
304706f2543Smrg	    double b = w[i] * t[i] - u[i] * p[i];
305706f2543Smrg	    if (b != 0) {
306706f2543Smrg		f = a/b;
307706f2543Smrg		break;
308706f2543Smrg	    }
309706f2543Smrg	}
310706f2543Smrg
311706f2543Smrg	/* Solve for the resulting transform vector */
312706f2543Smrg	for (i = 0; i < 2; i++) {
313706f2543Smrg	    if (u[i])
314706f2543Smrg		d.v[1-i] = (t[i] * f - q[i]) / u[i];
315706f2543Smrg	    else if (w[1])
316706f2543Smrg		d.v[1-i] = (p[i] * f - v[i]) / w[i];
317706f2543Smrg	    else
318706f2543Smrg		d.v[1-i] = 0;
319706f2543Smrg	}
320706f2543Smrg	*new_pan_x = old_pan_x - floor (d.v[0] + 0.5);
321706f2543Smrg	*new_pan_y = old_pan_y - floor (d.v[1] + 0.5);
322706f2543Smrg    } else {
323706f2543Smrg	*new_pan_x = screen_x - crtc_x;
324706f2543Smrg	*new_pan_y = screen_y - crtc_y;
325706f2543Smrg    }
326706f2543Smrg}
327706f2543Smrg
328706f2543Smrgstatic void
329706f2543Smrgxf86RandR13Pan (xf86CrtcPtr crtc, int x, int y)
330706f2543Smrg{
331706f2543Smrg    int newX, newY;
332706f2543Smrg    int width, height;
333706f2543Smrg    Bool panned = FALSE;
334706f2543Smrg
335706f2543Smrg    if (crtc->version < 2)
336706f2543Smrg	return;
337706f2543Smrg
338706f2543Smrg    if (! crtc->enabled						||
339706f2543Smrg	(crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1	&&
340706f2543Smrg	 crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1))
341706f2543Smrg	return;
342706f2543Smrg
343706f2543Smrg    newX   = crtc->x;
344706f2543Smrg    newY   = crtc->y;
345706f2543Smrg    width  = crtc->mode.HDisplay;
346706f2543Smrg    height = crtc->mode.VDisplay;
347706f2543Smrg
348706f2543Smrg    if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 ||
349706f2543Smrg	 (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) &&
350706f2543Smrg	(crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 ||
351706f2543Smrg	 (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2)))
352706f2543Smrg    {
353706f2543Smrg	struct pict_f_vector    c;
354706f2543Smrg
355706f2543Smrg	/*
356706f2543Smrg	 * Pre-clip the mouse position to the panning area so that we don't
357706f2543Smrg	 * push the crtc outside. This doesn't deal with changes to the
358706f2543Smrg	 * panning values, only mouse position changes.
359706f2543Smrg	 */
360706f2543Smrg	if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1)
361706f2543Smrg	{
362706f2543Smrg	    if (x < crtc->panningTotalArea.x1)
363706f2543Smrg		x = crtc->panningTotalArea.x1;
364706f2543Smrg	    if (x >= crtc->panningTotalArea.x2)
365706f2543Smrg		x = crtc->panningTotalArea.x2 - 1;
366706f2543Smrg	}
367706f2543Smrg	if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1)
368706f2543Smrg	{
369706f2543Smrg	    if (y < crtc->panningTotalArea.y1)
370706f2543Smrg		y = crtc->panningTotalArea.y1;
371706f2543Smrg	    if (y >= crtc->panningTotalArea.y2)
372706f2543Smrg		y = crtc->panningTotalArea.y2 - 1;
373706f2543Smrg	}
374706f2543Smrg
375706f2543Smrg	c.v[0] = x;
376706f2543Smrg	c.v[1] = y;
377706f2543Smrg	c.v[2] = 1.0;
378706f2543Smrg	if (crtc->transform_in_use) {
379706f2543Smrg	    pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c);
380706f2543Smrg	} else {
381706f2543Smrg	    c.v[0] -= crtc->x;
382706f2543Smrg	    c.v[1] -= crtc->y;
383706f2543Smrg	}
384706f2543Smrg
385706f2543Smrg	if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
386706f2543Smrg	    if (c.v[0] < crtc->panningBorder[0]) {
387706f2543Smrg		c.v[0] = crtc->panningBorder[0];
388706f2543Smrg		panned = TRUE;
389706f2543Smrg	    }
390706f2543Smrg	    if (c.v[0] >= width - crtc->panningBorder[2]) {
391706f2543Smrg		c.v[0] = width - crtc->panningBorder[2] - 1;
392706f2543Smrg		panned = TRUE;
393706f2543Smrg	    }
394706f2543Smrg	}
395706f2543Smrg	if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
396706f2543Smrg	    if (c.v[1] < crtc->panningBorder[1]) {
397706f2543Smrg		c.v[1] = crtc->panningBorder[1];
398706f2543Smrg		panned = TRUE;
399706f2543Smrg	    }
400706f2543Smrg	    if (c.v[1] >= height - crtc->panningBorder[3]) {
401706f2543Smrg		c.v[1] = height - crtc->panningBorder[3] - 1;
402706f2543Smrg		panned = TRUE;
403706f2543Smrg	    }
404706f2543Smrg	}
405706f2543Smrg	if (panned)
406706f2543Smrg	    xf86ComputeCrtcPan (crtc->transform_in_use,
407706f2543Smrg				&crtc->f_framebuffer_to_crtc,
408706f2543Smrg				x, y, c.v[0], c.v[1],
409706f2543Smrg				newX, newY, &newX, &newY);
410706f2543Smrg    }
411706f2543Smrg
412706f2543Smrg    /*
413706f2543Smrg     * Ensure that the crtc is within the panning region.
414706f2543Smrg     *
415706f2543Smrg     * XXX This computation only works when we do not have a transform
416706f2543Smrg     * in use.
417706f2543Smrg     */
418706f2543Smrg    if (!crtc->transform_in_use)
419706f2543Smrg    {
420706f2543Smrg	/* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */
421706f2543Smrg	if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
422706f2543Smrg	    if (newX > crtc->panningTotalArea.x2 - width)
423706f2543Smrg		newX =  crtc->panningTotalArea.x2 - width;
424706f2543Smrg	    if (newX <  crtc->panningTotalArea.x1)
425706f2543Smrg		newX =  crtc->panningTotalArea.x1;
426706f2543Smrg	}
427706f2543Smrg	if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
428706f2543Smrg	    if (newY > crtc->panningTotalArea.y2 - height)
429706f2543Smrg		newY =  crtc->panningTotalArea.y2 - height;
430706f2543Smrg	    if (newY <  crtc->panningTotalArea.y1)
431706f2543Smrg		newY =  crtc->panningTotalArea.y1;
432706f2543Smrg	}
433706f2543Smrg    }
434706f2543Smrg    if (newX != crtc->x || newY != crtc->y)
435706f2543Smrg	xf86CrtcSetOrigin (crtc, newX, newY);
436706f2543Smrg}
437706f2543Smrg
438706f2543Smrgstatic Bool
439706f2543Smrgxf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations)
440706f2543Smrg{
441706f2543Smrg    RRScreenSizePtr	    pSize;
442706f2543Smrg    ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
443706f2543Smrg    XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
444706f2543Smrg    DisplayModePtr	    mode;
445706f2543Smrg    int			    refresh0 = 60;
446706f2543Smrg    int			    maxX = 0, maxY = 0;
447706f2543Smrg
448706f2543Smrg    *rotations = randrp->supported_rotations;
449706f2543Smrg
450706f2543Smrg    if (randrp->virtualX == -1 || randrp->virtualY == -1)
451706f2543Smrg    {
452706f2543Smrg	randrp->virtualX = scrp->virtualX;
453706f2543Smrg	randrp->virtualY = scrp->virtualY;
454706f2543Smrg    }
455706f2543Smrg
456706f2543Smrg    /* Re-probe the outputs for new monitors or modes */
457706f2543Smrg    if (scrp->vtSema)
458706f2543Smrg    {
459706f2543Smrg	xf86ProbeOutputModes (scrp, 0, 0);
460706f2543Smrg	xf86SetScrnInfoModes (scrp);
461706f2543Smrg    }
462706f2543Smrg
463706f2543Smrg    for (mode = scrp->modes; ; mode = mode->next)
464706f2543Smrg    {
465706f2543Smrg	int refresh = xf86RandR12ModeRefresh (mode);
466706f2543Smrg	if (randrp->maxX == 0 || randrp->maxY == 0)
467706f2543Smrg	{
468706f2543Smrg		if (maxX < mode->HDisplay)
469706f2543Smrg			maxX = mode->HDisplay;
470706f2543Smrg		if (maxY < mode->VDisplay)
471706f2543Smrg			maxY = mode->VDisplay;
472706f2543Smrg	}
473706f2543Smrg	if (mode == scrp->modes)
474706f2543Smrg	    refresh0 = refresh;
475706f2543Smrg	pSize = RRRegisterSize (pScreen,
476706f2543Smrg				mode->HDisplay, mode->VDisplay,
477706f2543Smrg				randrp->mmWidth, randrp->mmHeight);
478706f2543Smrg	if (!pSize)
479706f2543Smrg	    return FALSE;
480706f2543Smrg	RRRegisterRate (pScreen, pSize, refresh);
481706f2543Smrg
482706f2543Smrg	if (xf86ModesEqual(mode, scrp->currentMode))
483706f2543Smrg	{
484706f2543Smrg	    RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize);
485706f2543Smrg	}
486706f2543Smrg	if (mode->next == scrp->modes)
487706f2543Smrg	    break;
488706f2543Smrg    }
489706f2543Smrg
490706f2543Smrg    if (randrp->maxX == 0 || randrp->maxY == 0)
491706f2543Smrg    {
492706f2543Smrg	randrp->maxX = maxX;
493706f2543Smrg	randrp->maxY = maxY;
494706f2543Smrg    }
495706f2543Smrg
496706f2543Smrg    return TRUE;
497706f2543Smrg}
498706f2543Smrg
499706f2543Smrgstatic Bool
500706f2543Smrgxf86RandR12SetMode (ScreenPtr	    pScreen,
501706f2543Smrg		  DisplayModePtr    mode,
502706f2543Smrg		  Bool		    useVirtual,
503706f2543Smrg		  int		    mmWidth,
504706f2543Smrg		  int		    mmHeight)
505706f2543Smrg{
506706f2543Smrg    ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
507706f2543Smrg    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
508706f2543Smrg    int			oldWidth = pScreen->width;
509706f2543Smrg    int			oldHeight = pScreen->height;
510706f2543Smrg    int			oldmmWidth = pScreen->mmWidth;
511706f2543Smrg    int			oldmmHeight = pScreen->mmHeight;
512706f2543Smrg    WindowPtr		pRoot = pScreen->root;
513706f2543Smrg    DisplayModePtr      currentMode = NULL;
514706f2543Smrg    Bool 		ret = TRUE;
515706f2543Smrg
516706f2543Smrg    if (pRoot)
517706f2543Smrg	(*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
518706f2543Smrg    if (useVirtual)
519706f2543Smrg    {
520706f2543Smrg	scrp->virtualX = randrp->virtualX;
521706f2543Smrg	scrp->virtualY = randrp->virtualY;
522706f2543Smrg    }
523706f2543Smrg    else
524706f2543Smrg    {
525706f2543Smrg	scrp->virtualX = mode->HDisplay;
526706f2543Smrg	scrp->virtualY = mode->VDisplay;
527706f2543Smrg    }
528706f2543Smrg
529706f2543Smrg    if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270))
530706f2543Smrg    {
531706f2543Smrg	/* If the screen is rotated 90 or 270 degrees, swap the sizes. */
532706f2543Smrg	pScreen->width = scrp->virtualY;
533706f2543Smrg	pScreen->height = scrp->virtualX;
534706f2543Smrg	pScreen->mmWidth = mmHeight;
535706f2543Smrg	pScreen->mmHeight = mmWidth;
536706f2543Smrg    }
537706f2543Smrg    else
538706f2543Smrg    {
539706f2543Smrg	pScreen->width = scrp->virtualX;
540706f2543Smrg	pScreen->height = scrp->virtualY;
541706f2543Smrg	pScreen->mmWidth = mmWidth;
542706f2543Smrg	pScreen->mmHeight = mmHeight;
543706f2543Smrg    }
544706f2543Smrg    if (scrp->currentMode == mode) {
545706f2543Smrg        /* Save current mode */
546706f2543Smrg        currentMode = scrp->currentMode;
547706f2543Smrg        /* Reset, just so we ensure the drivers SwitchMode is called */
548706f2543Smrg        scrp->currentMode = NULL;
549706f2543Smrg    }
550706f2543Smrg    /*
551706f2543Smrg     * We know that if the driver failed to SwitchMode to the rotated
552706f2543Smrg     * version, then it should revert back to it's prior mode.
553706f2543Smrg     */
554706f2543Smrg    if (!xf86SwitchMode (pScreen, mode))
555706f2543Smrg    {
556706f2543Smrg        ret = FALSE;
557706f2543Smrg	scrp->virtualX = pScreen->width = oldWidth;
558706f2543Smrg	scrp->virtualY = pScreen->height = oldHeight;
559706f2543Smrg	pScreen->mmWidth = oldmmWidth;
560706f2543Smrg	pScreen->mmHeight = oldmmHeight;
561706f2543Smrg        scrp->currentMode = currentMode;
562706f2543Smrg    }
563706f2543Smrg
564706f2543Smrg    /*
565706f2543Smrg     * Make sure the layout is correct
566706f2543Smrg     */
567706f2543Smrg    xf86ReconfigureLayout();
568706f2543Smrg
569706f2543Smrg    /*
570706f2543Smrg     * Make sure the whole screen is visible
571706f2543Smrg     */
572706f2543Smrg    xf86SetViewport (pScreen, pScreen->width, pScreen->height);
573706f2543Smrg    xf86SetViewport (pScreen, 0, 0);
574706f2543Smrg    if (pRoot)
575706f2543Smrg	(*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE);
576706f2543Smrg    return ret;
577706f2543Smrg}
578706f2543Smrg
579706f2543SmrgBool
580706f2543Smrgxf86RandR12SetConfig (ScreenPtr		pScreen,
581706f2543Smrg		    Rotation		rotation,
582706f2543Smrg		    int			rate,
583706f2543Smrg		    RRScreenSizePtr	pSize)
584706f2543Smrg{
585706f2543Smrg    ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
586706f2543Smrg    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
587706f2543Smrg    DisplayModePtr	mode;
588706f2543Smrg    int			px, py;
589706f2543Smrg    Bool		useVirtual = FALSE;
590706f2543Smrg    int			maxX = 0, maxY = 0;
591706f2543Smrg    Rotation		oldRotation = randrp->rotation;
592706f2543Smrg
593706f2543Smrg    randrp->rotation = rotation;
594706f2543Smrg
595706f2543Smrg    if (randrp->virtualX == -1 || randrp->virtualY == -1)
596706f2543Smrg    {
597706f2543Smrg	randrp->virtualX = scrp->virtualX;
598706f2543Smrg	randrp->virtualY = scrp->virtualY;
599706f2543Smrg    }
600706f2543Smrg
601706f2543Smrg    miPointerGetPosition (inputInfo.pointer, &px, &py);
602706f2543Smrg    for (mode = scrp->modes; ; mode = mode->next)
603706f2543Smrg    {
604706f2543Smrg	if (randrp->maxX == 0 || randrp->maxY == 0)
605706f2543Smrg	{
606706f2543Smrg		if (maxX < mode->HDisplay)
607706f2543Smrg			maxX = mode->HDisplay;
608706f2543Smrg		if (maxY < mode->VDisplay)
609706f2543Smrg			maxY = mode->VDisplay;
610706f2543Smrg	}
611706f2543Smrg	if (mode->HDisplay == pSize->width &&
612706f2543Smrg	    mode->VDisplay == pSize->height &&
613706f2543Smrg	    (rate == 0 || xf86RandR12ModeRefresh (mode) == rate))
614706f2543Smrg	    break;
615706f2543Smrg	if (mode->next == scrp->modes)
616706f2543Smrg	{
617706f2543Smrg	    if (pSize->width == randrp->virtualX &&
618706f2543Smrg		pSize->height == randrp->virtualY)
619706f2543Smrg	    {
620706f2543Smrg		mode = scrp->modes;
621706f2543Smrg		useVirtual = TRUE;
622706f2543Smrg		break;
623706f2543Smrg	    }
624706f2543Smrg    	    if (randrp->maxX == 0 || randrp->maxY == 0)
625706f2543Smrg    	    {
626706f2543Smrg		randrp->maxX = maxX;
627706f2543Smrg		randrp->maxY = maxY;
628706f2543Smrg    	    }
629706f2543Smrg	    return FALSE;
630706f2543Smrg	}
631706f2543Smrg    }
632706f2543Smrg
633706f2543Smrg    if (randrp->maxX == 0 || randrp->maxY == 0)
634706f2543Smrg    {
635706f2543Smrg	randrp->maxX = maxX;
636706f2543Smrg	randrp->maxY = maxY;
637706f2543Smrg    }
638706f2543Smrg
639706f2543Smrg    if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth,
640706f2543Smrg			   pSize->mmHeight)) {
641706f2543Smrg        randrp->rotation = oldRotation;
642706f2543Smrg	return FALSE;
643706f2543Smrg    }
644706f2543Smrg
645706f2543Smrg    /*
646706f2543Smrg     * Move the cursor back where it belongs; SwitchMode repositions it
647706f2543Smrg     */
648706f2543Smrg    if (pScreen == miPointerGetScreen(inputInfo.pointer))
649706f2543Smrg    {
650706f2543Smrg        px = (px >= pScreen->width ? (pScreen->width - 1) : px);
651706f2543Smrg        py = (py >= pScreen->height ? (pScreen->height - 1) : py);
652706f2543Smrg
653706f2543Smrg	xf86SetViewport(pScreen, px, py);
654706f2543Smrg
655706f2543Smrg	(*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE);
656706f2543Smrg    }
657706f2543Smrg
658706f2543Smrg    return TRUE;
659706f2543Smrg}
660706f2543Smrg
661706f2543Smrgstatic Bool
662706f2543Smrgxf86RandR12ScreenSetSize (ScreenPtr	pScreen,
663706f2543Smrg			CARD16		width,
664706f2543Smrg			CARD16		height,
665706f2543Smrg			CARD32		mmWidth,
666706f2543Smrg			CARD32		mmHeight)
667706f2543Smrg{
668706f2543Smrg    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
669706f2543Smrg    ScrnInfoPtr		pScrn = XF86SCRNINFO(pScreen);
670706f2543Smrg    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
671706f2543Smrg    WindowPtr		pRoot = pScreen->root;
672706f2543Smrg    PixmapPtr		pScrnPix;
673706f2543Smrg    Bool		ret = FALSE;
674706f2543Smrg    int                 c;
675706f2543Smrg
676706f2543Smrg    if (xf86RandR12Key) {
677706f2543Smrg        if (randrp->virtualX == -1 || randrp->virtualY == -1)
678706f2543Smrg        {
679706f2543Smrg	    randrp->virtualX = pScrn->virtualX;
680706f2543Smrg	    randrp->virtualY = pScrn->virtualY;
681706f2543Smrg        }
682706f2543Smrg    }
683706f2543Smrg    if (pRoot && pScrn->vtSema)
684706f2543Smrg	(*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE);
685706f2543Smrg
686706f2543Smrg    /* Let the driver update virtualX and virtualY */
687706f2543Smrg    if (!(*config->funcs->resize)(pScrn, width, height))
688706f2543Smrg	goto finish;
689706f2543Smrg
690706f2543Smrg    ret = TRUE;
691706f2543Smrg    /* Update panning information */
692706f2543Smrg    for (c = 0; c < config->num_crtc; c++) {
693706f2543Smrg	xf86CrtcPtr crtc = config->crtc[c];
694706f2543Smrg	if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 ||
695706f2543Smrg	    crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
696706f2543Smrg	    if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1)
697706f2543Smrg		crtc->panningTotalArea.x2 += width  - pScreen->width;
698706f2543Smrg	    if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1)
699706f2543Smrg		crtc->panningTotalArea.y2 += height - pScreen->height;
700706f2543Smrg	    if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1)
701706f2543Smrg		crtc->panningTrackingArea.x2 += width  - pScreen->width;
702706f2543Smrg	    if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1)
703706f2543Smrg		crtc->panningTrackingArea.y2 += height - pScreen->height;
704706f2543Smrg	    xf86RandR13VerifyPanningArea (crtc, width, height);
705706f2543Smrg	    xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
706706f2543Smrg	}
707706f2543Smrg    }
708706f2543Smrg
709706f2543Smrg    pScrnPix = (*pScreen->GetScreenPixmap)(pScreen);
710706f2543Smrg    pScreen->width = pScrnPix->drawable.width = width;
711706f2543Smrg    pScreen->height = pScrnPix->drawable.height = height;
712706f2543Smrg    randrp->mmWidth = pScreen->mmWidth = mmWidth;
713706f2543Smrg    randrp->mmHeight = pScreen->mmHeight = mmHeight;
714706f2543Smrg
715706f2543Smrg    xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1);
716706f2543Smrg    xf86SetViewport (pScreen, 0, 0);
717706f2543Smrg
718706f2543Smrgfinish:
719706f2543Smrg    if (pRoot && pScrn->vtSema)
720706f2543Smrg	(*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE);
721706f2543Smrg#if RANDR_12_INTERFACE
722706f2543Smrg    if (xf86RandR12Key && pScreen->root && ret)
723706f2543Smrg	RRScreenSizeNotify (pScreen);
724706f2543Smrg#endif
725706f2543Smrg    return ret;
726706f2543Smrg}
727706f2543Smrg
728706f2543SmrgRotation
729706f2543Smrgxf86RandR12GetRotation(ScreenPtr pScreen)
730706f2543Smrg{
731706f2543Smrg    XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
732706f2543Smrg
733706f2543Smrg    return randrp->rotation;
734706f2543Smrg}
735706f2543Smrg
736706f2543SmrgBool
737706f2543Smrgxf86RandR12CreateScreenResources (ScreenPtr pScreen)
738706f2543Smrg{
739706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
740706f2543Smrg    xf86CrtcConfigPtr   config;
741706f2543Smrg    XF86RandRInfoPtr	randrp;
742706f2543Smrg    int			c;
743706f2543Smrg    int			width, height;
744706f2543Smrg    int			mmWidth, mmHeight;
745706f2543Smrg#ifdef PANORAMIX
746706f2543Smrg    /* XXX disable RandR when using Xinerama */
747706f2543Smrg    if (!noPanoramiXExtension)
748706f2543Smrg	return TRUE;
749706f2543Smrg#endif
750706f2543Smrg
751706f2543Smrg    config = XF86_CRTC_CONFIG_PTR(pScrn);
752706f2543Smrg    randrp = XF86RANDRINFO(pScreen);
753706f2543Smrg    /*
754706f2543Smrg     * Compute size of screen
755706f2543Smrg     */
756706f2543Smrg    width = 0; height = 0;
757706f2543Smrg    for (c = 0; c < config->num_crtc; c++)
758706f2543Smrg    {
759706f2543Smrg	xf86CrtcPtr crtc = config->crtc[c];
760706f2543Smrg	int	    crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
761706f2543Smrg	int	    crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
762706f2543Smrg
763706f2543Smrg	if (crtc->enabled) {
764706f2543Smrg	    if (crtc_width > width)
765706f2543Smrg		width = crtc_width;
766706f2543Smrg	    if (crtc_height > height)
767706f2543Smrg		height = crtc_height;
768706f2543Smrg	    if (crtc->panningTotalArea.x2 > width)
769706f2543Smrg		width = crtc->panningTotalArea.x2;
770706f2543Smrg	    if (crtc->panningTotalArea.y2 > height)
771706f2543Smrg		height = crtc->panningTotalArea.y2;
772706f2543Smrg	}
773706f2543Smrg    }
774706f2543Smrg
775706f2543Smrg    if (width && height)
776706f2543Smrg    {
777706f2543Smrg	/*
778706f2543Smrg	 * Compute physical size of screen
779706f2543Smrg	 */
780706f2543Smrg	if (monitorResolution)
781706f2543Smrg	{
782706f2543Smrg	    mmWidth = width * 25.4 / monitorResolution;
783706f2543Smrg	    mmHeight = height * 25.4 / monitorResolution;
784706f2543Smrg	}
785706f2543Smrg	else
786706f2543Smrg	{
787706f2543Smrg	    xf86OutputPtr   output = xf86CompatOutput(pScrn);
788706f2543Smrg
789706f2543Smrg	    if (output &&
790706f2543Smrg		output->conf_monitor &&
791706f2543Smrg		(output->conf_monitor->mon_width  > 0 &&
792706f2543Smrg		 output->conf_monitor->mon_height > 0))
793706f2543Smrg	    {
794706f2543Smrg		/*
795706f2543Smrg		 * Prefer user configured DisplaySize
796706f2543Smrg		 */
797706f2543Smrg		mmWidth = output->conf_monitor->mon_width;
798706f2543Smrg		mmHeight = output->conf_monitor->mon_height;
799706f2543Smrg	    }
800706f2543Smrg	    else
801706f2543Smrg	    {
802706f2543Smrg		/*
803706f2543Smrg		 * Otherwise, just set the screen to DEFAULT_DPI
804706f2543Smrg		 */
805706f2543Smrg		mmWidth = width * 25.4 / DEFAULT_DPI;
806706f2543Smrg		mmHeight = height * 25.4 / DEFAULT_DPI;
807706f2543Smrg	    }
808706f2543Smrg	}
809706f2543Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
810706f2543Smrg		   "Setting screen physical size to %d x %d\n",
811706f2543Smrg		   mmWidth, mmHeight);
812706f2543Smrg	/*
813706f2543Smrg	 * This is the initial setting of the screen size.
814706f2543Smrg	 * We have to pre-set it here, otherwise panning would be adapted
815706f2543Smrg	 * to the new screen size.
816706f2543Smrg	 */
817706f2543Smrg	pScreen->width  = width;
818706f2543Smrg	pScreen->height = height;
819706f2543Smrg	xf86RandR12ScreenSetSize (pScreen,
820706f2543Smrg				  width,
821706f2543Smrg				  height,
822706f2543Smrg				  mmWidth,
823706f2543Smrg				  mmHeight);
824706f2543Smrg    }
825706f2543Smrg
826706f2543Smrg    if (xf86RandR12Key == NULL)
827706f2543Smrg	return TRUE;
828706f2543Smrg
829706f2543Smrg    if (randrp->virtualX == -1 || randrp->virtualY == -1)
830706f2543Smrg    {
831706f2543Smrg	randrp->virtualX = pScrn->virtualX;
832706f2543Smrg	randrp->virtualY = pScrn->virtualY;
833706f2543Smrg    }
834706f2543Smrg    xf86CrtcSetScreenSubpixelOrder (pScreen);
835706f2543Smrg#if RANDR_12_INTERFACE
836706f2543Smrg    if (xf86RandR12CreateScreenResources12 (pScreen))
837706f2543Smrg	return TRUE;
838706f2543Smrg#endif
839706f2543Smrg    return TRUE;
840706f2543Smrg}
841706f2543Smrg
842706f2543Smrg
843706f2543SmrgBool
844706f2543Smrgxf86RandR12Init (ScreenPtr pScreen)
845706f2543Smrg{
846706f2543Smrg    rrScrPrivPtr	rp;
847706f2543Smrg    XF86RandRInfoPtr	randrp;
848706f2543Smrg
849706f2543Smrg#ifdef PANORAMIX
850706f2543Smrg    /* XXX disable RandR when using Xinerama */
851706f2543Smrg    if (!noPanoramiXExtension)
852706f2543Smrg    {
853706f2543Smrg        if (xf86NumScreens == 1)
854706f2543Smrg            noPanoramiXExtension = TRUE;
855706f2543Smrg        else
856706f2543Smrg            return TRUE;
857706f2543Smrg    }
858706f2543Smrg#endif
859706f2543Smrg
860706f2543Smrg    if (xf86RandR12Generation != serverGeneration)
861706f2543Smrg	xf86RandR12Generation = serverGeneration;
862706f2543Smrg
863706f2543Smrg    xf86RandR12Key = &xf86RandR12KeyRec;
864706f2543Smrg    if (!dixRegisterPrivateKey(&xf86RandR12KeyRec, PRIVATE_SCREEN, 0))
865706f2543Smrg	return FALSE;
866706f2543Smrg
867706f2543Smrg    randrp = malloc(sizeof (XF86RandRInfoRec));
868706f2543Smrg    if (!randrp)
869706f2543Smrg	return FALSE;
870706f2543Smrg
871706f2543Smrg    if (!RRScreenInit(pScreen))
872706f2543Smrg    {
873706f2543Smrg	free(randrp);
874706f2543Smrg	return FALSE;
875706f2543Smrg    }
876706f2543Smrg    rp = rrGetScrPriv(pScreen);
877706f2543Smrg    rp->rrGetInfo = xf86RandR12GetInfo;
878706f2543Smrg    rp->rrSetConfig = xf86RandR12SetConfig;
879706f2543Smrg
880706f2543Smrg    randrp->virtualX = -1;
881706f2543Smrg    randrp->virtualY = -1;
882706f2543Smrg    randrp->mmWidth = pScreen->mmWidth;
883706f2543Smrg    randrp->mmHeight = pScreen->mmHeight;
884706f2543Smrg
885706f2543Smrg    randrp->rotation = RR_Rotate_0; /* initial rotated mode */
886706f2543Smrg
887706f2543Smrg    randrp->supported_rotations = RR_Rotate_0;
888706f2543Smrg
889706f2543Smrg    randrp->maxX = randrp->maxY = 0;
890706f2543Smrg
891706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp);
892706f2543Smrg
893706f2543Smrg#if RANDR_12_INTERFACE
894706f2543Smrg    if (!xf86RandR12Init12 (pScreen))
895706f2543Smrg	return FALSE;
896706f2543Smrg#endif
897706f2543Smrg    return TRUE;
898706f2543Smrg}
899706f2543Smrg
900706f2543Smrgvoid
901706f2543Smrgxf86RandR12CloseScreen (ScreenPtr pScreen)
902706f2543Smrg{
903706f2543Smrg    XF86RandRInfoPtr	randrp;
904706f2543Smrg
905706f2543Smrg    if (xf86RandR12Key == NULL)
906706f2543Smrg	return;
907706f2543Smrg
908706f2543Smrg    randrp = XF86RANDRINFO(pScreen);
909706f2543Smrg#if RANDR_12_INTERFACE
910706f2543Smrg    xf86Screens[pScreen->myNum]->EnterVT = randrp->orig_EnterVT;
911706f2543Smrg#endif
912706f2543Smrg
913706f2543Smrg    free(randrp);
914706f2543Smrg}
915706f2543Smrg
916706f2543Smrgvoid
917706f2543Smrgxf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations)
918706f2543Smrg{
919706f2543Smrg    XF86RandRInfoPtr	randrp;
920706f2543Smrg#if RANDR_12_INTERFACE
921706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
922706f2543Smrg    int			c;
923706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
924706f2543Smrg#endif
925706f2543Smrg
926706f2543Smrg    if (xf86RandR12Key == NULL)
927706f2543Smrg	return;
928706f2543Smrg
929706f2543Smrg    randrp = XF86RANDRINFO(pScreen);
930706f2543Smrg#if RANDR_12_INTERFACE
931706f2543Smrg    for (c = 0; c < config->num_crtc; c++) {
932706f2543Smrg	xf86CrtcPtr    crtc = config->crtc[c];
933706f2543Smrg
934706f2543Smrg	RRCrtcSetRotations (crtc->randr_crtc, rotations);
935706f2543Smrg    }
936706f2543Smrg#endif
937706f2543Smrg    randrp->supported_rotations = rotations;
938706f2543Smrg}
939706f2543Smrg
940706f2543Smrgvoid
941706f2543Smrgxf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms)
942706f2543Smrg{
943706f2543Smrg    XF86RandRInfoPtr	randrp;
944706f2543Smrg#if RANDR_13_INTERFACE
945706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
946706f2543Smrg    int			c;
947706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
948706f2543Smrg#endif
949706f2543Smrg
950706f2543Smrg    if (xf86RandR12Key == NULL)
951706f2543Smrg	return;
952706f2543Smrg
953706f2543Smrg    randrp = XF86RANDRINFO(pScreen);
954706f2543Smrg#if RANDR_13_INTERFACE
955706f2543Smrg    for (c = 0; c < config->num_crtc; c++) {
956706f2543Smrg	xf86CrtcPtr    crtc = config->crtc[c];
957706f2543Smrg
958706f2543Smrg	RRCrtcSetTransformSupport (crtc->randr_crtc, transforms);
959706f2543Smrg    }
960706f2543Smrg#endif
961706f2543Smrg}
962706f2543Smrg
963706f2543Smrgvoid
964706f2543Smrgxf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
965706f2543Smrg{
966706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
967706f2543Smrg
968706f2543Smrg    if (xf86RandR12Generation != serverGeneration ||
969706f2543Smrg	XF86RANDRINFO(pScreen)->virtualX == -1)
970706f2543Smrg    {
971706f2543Smrg	*x = pScrn->virtualX;
972706f2543Smrg	*y = pScrn->virtualY;
973706f2543Smrg    } else {
974706f2543Smrg	XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
975706f2543Smrg
976706f2543Smrg	*x = randrp->virtualX;
977706f2543Smrg	*y = randrp->virtualY;
978706f2543Smrg    }
979706f2543Smrg}
980706f2543Smrg
981706f2543Smrg#if RANDR_12_INTERFACE
982706f2543Smrg
983706f2543Smrg#define FLAG_BITS (RR_HSyncPositive | \
984706f2543Smrg		   RR_HSyncNegative | \
985706f2543Smrg		   RR_VSyncPositive | \
986706f2543Smrg		   RR_VSyncNegative | \
987706f2543Smrg		   RR_Interlace | \
988706f2543Smrg		   RR_DoubleScan | \
989706f2543Smrg		   RR_CSync | \
990706f2543Smrg		   RR_CSyncPositive | \
991706f2543Smrg		   RR_CSyncNegative | \
992706f2543Smrg		   RR_HSkewPresent | \
993706f2543Smrg		   RR_BCast | \
994706f2543Smrg		   RR_PixelMultiplex | \
995706f2543Smrg		   RR_DoubleClock | \
996706f2543Smrg		   RR_ClockDivideBy2)
997706f2543Smrg
998706f2543Smrgstatic Bool
999706f2543Smrgxf86RandRModeMatches (RRModePtr		randr_mode,
1000706f2543Smrg		      DisplayModePtr	mode)
1001706f2543Smrg{
1002706f2543Smrg#if 0
1003706f2543Smrg    if (match_name)
1004706f2543Smrg    {
1005706f2543Smrg	/* check for same name */
1006706f2543Smrg	int	len = strlen (mode->name);
1007706f2543Smrg	if (randr_mode->mode.nameLength != len)			return FALSE;
1008706f2543Smrg	if (memcmp (randr_mode->name, mode->name, len) != 0)	return FALSE;
1009706f2543Smrg    }
1010706f2543Smrg#endif
1011706f2543Smrg
1012706f2543Smrg    /* check for same timings */
1013706f2543Smrg    if (randr_mode->mode.dotClock / 1000 != mode->Clock)    return FALSE;
1014706f2543Smrg    if (randr_mode->mode.width        != mode->HDisplay)    return FALSE;
1015706f2543Smrg    if (randr_mode->mode.hSyncStart   != mode->HSyncStart)  return FALSE;
1016706f2543Smrg    if (randr_mode->mode.hSyncEnd     != mode->HSyncEnd)    return FALSE;
1017706f2543Smrg    if (randr_mode->mode.hTotal       != mode->HTotal)	    return FALSE;
1018706f2543Smrg    if (randr_mode->mode.hSkew        != mode->HSkew)	    return FALSE;
1019706f2543Smrg    if (randr_mode->mode.height       != mode->VDisplay)    return FALSE;
1020706f2543Smrg    if (randr_mode->mode.vSyncStart   != mode->VSyncStart)  return FALSE;
1021706f2543Smrg    if (randr_mode->mode.vSyncEnd     != mode->VSyncEnd)    return FALSE;
1022706f2543Smrg    if (randr_mode->mode.vTotal       != mode->VTotal)	    return FALSE;
1023706f2543Smrg
1024706f2543Smrg    /* check for same flags (using only the XF86 valid flag bits) */
1025706f2543Smrg    if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
1026706f2543Smrg	return FALSE;
1027706f2543Smrg
1028706f2543Smrg    /* everything matches */
1029706f2543Smrg    return TRUE;
1030706f2543Smrg}
1031706f2543Smrg
1032706f2543Smrgstatic Bool
1033706f2543Smrgxf86RandR12CrtcNotify (RRCrtcPtr	randr_crtc)
1034706f2543Smrg{
1035706f2543Smrg    ScreenPtr		pScreen = randr_crtc->pScreen;
1036706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1037706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1038706f2543Smrg    RRModePtr		randr_mode = NULL;
1039706f2543Smrg    int			x;
1040706f2543Smrg    int			y;
1041706f2543Smrg    Rotation		rotation;
1042706f2543Smrg    int			numOutputs;
1043706f2543Smrg    RROutputPtr		*randr_outputs;
1044706f2543Smrg    RROutputPtr		randr_output;
1045706f2543Smrg    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
1046706f2543Smrg    xf86OutputPtr	output;
1047706f2543Smrg    int			i, j;
1048706f2543Smrg    DisplayModePtr	mode = &crtc->mode;
1049706f2543Smrg    Bool		ret;
1050706f2543Smrg
1051706f2543Smrg    randr_outputs = malloc(config->num_output * sizeof (RROutputPtr));
1052706f2543Smrg    if (!randr_outputs)
1053706f2543Smrg	return FALSE;
1054706f2543Smrg    x = crtc->x;
1055706f2543Smrg    y = crtc->y;
1056706f2543Smrg    rotation = crtc->rotation;
1057706f2543Smrg    numOutputs = 0;
1058706f2543Smrg    randr_mode = NULL;
1059706f2543Smrg    for (i = 0; i < config->num_output; i++)
1060706f2543Smrg    {
1061706f2543Smrg	output = config->output[i];
1062706f2543Smrg	if (output->crtc == crtc)
1063706f2543Smrg	{
1064706f2543Smrg	    randr_output = output->randr_output;
1065706f2543Smrg	    randr_outputs[numOutputs++] = randr_output;
1066706f2543Smrg	    /*
1067706f2543Smrg	     * We make copies of modes, so pointer equality
1068706f2543Smrg	     * isn't sufficient
1069706f2543Smrg	     */
1070706f2543Smrg	    for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++)
1071706f2543Smrg	    {
1072706f2543Smrg		RRModePtr   m = (j < randr_output->numModes ?
1073706f2543Smrg				 randr_output->modes[j] :
1074706f2543Smrg				 randr_output->userModes[j-randr_output->numModes]);
1075706f2543Smrg
1076706f2543Smrg		if (xf86RandRModeMatches (m, mode))
1077706f2543Smrg		{
1078706f2543Smrg		    randr_mode = m;
1079706f2543Smrg		    break;
1080706f2543Smrg		}
1081706f2543Smrg	    }
1082706f2543Smrg	}
1083706f2543Smrg    }
1084706f2543Smrg    ret = RRCrtcNotify (randr_crtc, randr_mode, x, y,
1085706f2543Smrg			rotation,
1086706f2543Smrg			crtc->transformPresent ? &crtc->transform : NULL,
1087706f2543Smrg			numOutputs, randr_outputs);
1088706f2543Smrg    free(randr_outputs);
1089706f2543Smrg    return ret;
1090706f2543Smrg}
1091706f2543Smrg
1092706f2543Smrg/*
1093706f2543Smrg * Convert a RandR mode to a DisplayMode
1094706f2543Smrg */
1095706f2543Smrgstatic void
1096706f2543Smrgxf86RandRModeConvert (ScrnInfoPtr	scrn,
1097706f2543Smrg		      RRModePtr		randr_mode,
1098706f2543Smrg		      DisplayModePtr	mode)
1099706f2543Smrg{
1100706f2543Smrg    memset(mode, 0, sizeof(DisplayModeRec));
1101706f2543Smrg    mode->status = MODE_OK;
1102706f2543Smrg
1103706f2543Smrg    mode->Clock = randr_mode->mode.dotClock / 1000;
1104706f2543Smrg
1105706f2543Smrg    mode->HDisplay = randr_mode->mode.width;
1106706f2543Smrg    mode->HSyncStart = randr_mode->mode.hSyncStart;
1107706f2543Smrg    mode->HSyncEnd = randr_mode->mode.hSyncEnd;
1108706f2543Smrg    mode->HTotal = randr_mode->mode.hTotal;
1109706f2543Smrg    mode->HSkew = randr_mode->mode.hSkew;
1110706f2543Smrg
1111706f2543Smrg    mode->VDisplay = randr_mode->mode.height;
1112706f2543Smrg    mode->VSyncStart = randr_mode->mode.vSyncStart;
1113706f2543Smrg    mode->VSyncEnd = randr_mode->mode.vSyncEnd;
1114706f2543Smrg    mode->VTotal = randr_mode->mode.vTotal;
1115706f2543Smrg    mode->VScan = 0;
1116706f2543Smrg
1117706f2543Smrg    mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;
1118706f2543Smrg
1119706f2543Smrg    xf86SetModeCrtc (mode, scrn->adjustFlags);
1120706f2543Smrg}
1121706f2543Smrg
1122706f2543Smrgstatic Bool
1123706f2543Smrgxf86RandR12CrtcSet (ScreenPtr	    pScreen,
1124706f2543Smrg		    RRCrtcPtr	    randr_crtc,
1125706f2543Smrg		    RRModePtr	    randr_mode,
1126706f2543Smrg		    int		    x,
1127706f2543Smrg		    int		    y,
1128706f2543Smrg		    Rotation	    rotation,
1129706f2543Smrg		    int		    num_randr_outputs,
1130706f2543Smrg		    RROutputPtr	    *randr_outputs)
1131706f2543Smrg{
1132706f2543Smrg    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
1133706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1134706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1135706f2543Smrg    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
1136706f2543Smrg    RRTransformPtr	transform;
1137706f2543Smrg    Bool		changed = FALSE;
1138706f2543Smrg    int			o, ro;
1139706f2543Smrg    xf86CrtcPtr		*save_crtcs;
1140706f2543Smrg    Bool		save_enabled = crtc->enabled;
1141706f2543Smrg
1142706f2543Smrg    if (!crtc->scrn->vtSema)
1143706f2543Smrg	return FALSE;
1144706f2543Smrg
1145706f2543Smrg    save_crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr));
1146706f2543Smrg    if ((randr_mode != NULL) != crtc->enabled)
1147706f2543Smrg	changed = TRUE;
1148706f2543Smrg    else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode))
1149706f2543Smrg	changed = TRUE;
1150706f2543Smrg
1151706f2543Smrg    if (rotation != crtc->rotation)
1152706f2543Smrg	changed = TRUE;
1153706f2543Smrg
1154706f2543Smrg    transform = RRCrtcGetTransform (randr_crtc);
1155706f2543Smrg    if ((transform != NULL) != crtc->transformPresent)
1156706f2543Smrg	changed = TRUE;
1157706f2543Smrg    else if (transform && memcmp (&transform->transform, &crtc->transform.transform,
1158706f2543Smrg				  sizeof (transform->transform)) != 0)
1159706f2543Smrg	changed = TRUE;
1160706f2543Smrg
1161706f2543Smrg    if (x != crtc->x || y != crtc->y)
1162706f2543Smrg	changed = TRUE;
1163706f2543Smrg    for (o = 0; o < config->num_output; o++)
1164706f2543Smrg    {
1165706f2543Smrg	xf86OutputPtr  output = config->output[o];
1166706f2543Smrg	xf86CrtcPtr    new_crtc;
1167706f2543Smrg
1168706f2543Smrg	save_crtcs[o] = output->crtc;
1169706f2543Smrg
1170706f2543Smrg	if (output->crtc == crtc)
1171706f2543Smrg	    new_crtc = NULL;
1172706f2543Smrg	else
1173706f2543Smrg	    new_crtc = output->crtc;
1174706f2543Smrg	for (ro = 0; ro < num_randr_outputs; ro++)
1175706f2543Smrg	    if (output->randr_output == randr_outputs[ro])
1176706f2543Smrg	    {
1177706f2543Smrg		new_crtc = crtc;
1178706f2543Smrg		break;
1179706f2543Smrg	    }
1180706f2543Smrg	if (new_crtc != output->crtc)
1181706f2543Smrg	{
1182706f2543Smrg	    changed = TRUE;
1183706f2543Smrg	    output->crtc = new_crtc;
1184706f2543Smrg	}
1185706f2543Smrg    }
1186706f2543Smrg    for (ro = 0; ro < num_randr_outputs; ro++)
1187706f2543Smrg        if (randr_outputs[ro]->pendingProperties)
1188706f2543Smrg	    changed = TRUE;
1189706f2543Smrg
1190706f2543Smrg    /* XXX need device-independent mode setting code through an API */
1191706f2543Smrg    if (changed)
1192706f2543Smrg    {
1193706f2543Smrg	crtc->enabled = randr_mode != NULL;
1194706f2543Smrg
1195706f2543Smrg	if (randr_mode)
1196706f2543Smrg	{
1197706f2543Smrg	    DisplayModeRec  mode;
1198706f2543Smrg	    RRTransformPtr  transform = RRCrtcGetTransform (randr_crtc);
1199706f2543Smrg
1200706f2543Smrg	    xf86RandRModeConvert (pScrn, randr_mode, &mode);
1201706f2543Smrg	    if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y))
1202706f2543Smrg	    {
1203706f2543Smrg		crtc->enabled = save_enabled;
1204706f2543Smrg		for (o = 0; o < config->num_output; o++)
1205706f2543Smrg		{
1206706f2543Smrg		    xf86OutputPtr	output = config->output[o];
1207706f2543Smrg		    output->crtc = save_crtcs[o];
1208706f2543Smrg		}
1209706f2543Smrg		free(save_crtcs);
1210706f2543Smrg		return FALSE;
1211706f2543Smrg	    }
1212706f2543Smrg	    xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height);
1213706f2543Smrg	    xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
1214706f2543Smrg	    /*
1215706f2543Smrg	     * Save the last successful setting for EnterVT
1216706f2543Smrg	     */
1217706f2543Smrg	    crtc->desiredMode = mode;
1218706f2543Smrg	    crtc->desiredRotation = rotation;
1219706f2543Smrg	    if (transform) {
1220706f2543Smrg		crtc->desiredTransform = *transform;
1221706f2543Smrg		crtc->desiredTransformPresent = TRUE;
1222706f2543Smrg	    } else
1223706f2543Smrg		crtc->desiredTransformPresent = FALSE;
1224706f2543Smrg
1225706f2543Smrg	    crtc->desiredX = x;
1226706f2543Smrg	    crtc->desiredY = y;
1227706f2543Smrg	}
1228706f2543Smrg	xf86DisableUnusedFunctions (pScrn);
1229706f2543Smrg    }
1230706f2543Smrg    free(save_crtcs);
1231706f2543Smrg    return xf86RandR12CrtcNotify (randr_crtc);
1232706f2543Smrg}
1233706f2543Smrg
1234706f2543Smrgstatic Bool
1235706f2543Smrgxf86RandR12CrtcSetGamma (ScreenPtr    pScreen,
1236706f2543Smrg			 RRCrtcPtr    randr_crtc)
1237706f2543Smrg{
1238706f2543Smrg    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
1239706f2543Smrg
1240706f2543Smrg    if (crtc->funcs->gamma_set == NULL)
1241706f2543Smrg	return FALSE;
1242706f2543Smrg
1243706f2543Smrg    if (!crtc->scrn->vtSema)
1244706f2543Smrg	return TRUE;
1245706f2543Smrg
1246706f2543Smrg    /* Realloc local gamma if needed. */
1247706f2543Smrg    if (randr_crtc->gammaSize != crtc->gamma_size) {
1248706f2543Smrg        CARD16 *tmp_ptr;
1249706f2543Smrg        tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16));
1250706f2543Smrg        if (!tmp_ptr)
1251706f2543Smrg            return FALSE;
1252706f2543Smrg        crtc->gamma_red = tmp_ptr;
1253706f2543Smrg        crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
1254706f2543Smrg        crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
1255706f2543Smrg    }
1256706f2543Smrg
1257706f2543Smrg    crtc->gamma_size = randr_crtc->gammaSize;
1258706f2543Smrg    memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16));
1259706f2543Smrg    memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16));
1260706f2543Smrg    memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16));
1261706f2543Smrg
1262706f2543Smrg    /* Only set it when the crtc is actually running.
1263706f2543Smrg     * Otherwise it will be set when it's activated.
1264706f2543Smrg     */
1265706f2543Smrg    if (crtc->active)
1266706f2543Smrg	crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1267706f2543Smrg						crtc->gamma_blue, crtc->gamma_size);
1268706f2543Smrg
1269706f2543Smrg    return TRUE;
1270706f2543Smrg}
1271706f2543Smrg
1272706f2543Smrgstatic Bool
1273706f2543Smrgxf86RandR12CrtcGetGamma (ScreenPtr    pScreen,
1274706f2543Smrg			 RRCrtcPtr    randr_crtc)
1275706f2543Smrg{
1276706f2543Smrg    xf86CrtcPtr crtc = randr_crtc->devPrivate;
1277706f2543Smrg
1278706f2543Smrg    if (!crtc->gamma_size)
1279706f2543Smrg        return FALSE;
1280706f2543Smrg
1281706f2543Smrg    if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue)
1282706f2543Smrg        return FALSE;
1283706f2543Smrg
1284706f2543Smrg    /* Realloc randr gamma if needed. */
1285706f2543Smrg    if (randr_crtc->gammaSize != crtc->gamma_size) {
1286706f2543Smrg        CARD16 *tmp_ptr;
1287706f2543Smrg        tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16));
1288706f2543Smrg        if (!tmp_ptr)
1289706f2543Smrg            return FALSE;
1290706f2543Smrg        randr_crtc->gammaRed = tmp_ptr;
1291706f2543Smrg        randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size;
1292706f2543Smrg        randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size;
1293706f2543Smrg    }
1294706f2543Smrg    randr_crtc->gammaSize = crtc->gamma_size;
1295706f2543Smrg    memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16));
1296706f2543Smrg    memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16));
1297706f2543Smrg    memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16));
1298706f2543Smrg
1299706f2543Smrg    return TRUE;
1300706f2543Smrg}
1301706f2543Smrg
1302706f2543Smrgstatic Bool
1303706f2543Smrgxf86RandR12OutputSetProperty (ScreenPtr pScreen,
1304706f2543Smrg			      RROutputPtr randr_output,
1305706f2543Smrg			      Atom property,
1306706f2543Smrg			      RRPropertyValuePtr value)
1307706f2543Smrg{
1308706f2543Smrg    xf86OutputPtr output = randr_output->devPrivate;
1309706f2543Smrg
1310706f2543Smrg    /* If we don't have any property handler, then we don't care what the
1311706f2543Smrg     * user is setting properties to.
1312706f2543Smrg     */
1313706f2543Smrg    if (output->funcs->set_property == NULL)
1314706f2543Smrg	return TRUE;
1315706f2543Smrg
1316706f2543Smrg    /*
1317706f2543Smrg     * This function gets called even when vtSema is FALSE, as
1318706f2543Smrg     * drivers will need to remember the correct value to apply
1319706f2543Smrg     * when the VT switch occurs
1320706f2543Smrg     */
1321706f2543Smrg    return output->funcs->set_property(output, property, value);
1322706f2543Smrg}
1323706f2543Smrg
1324706f2543Smrgstatic Bool
1325706f2543Smrgxf86RandR13OutputGetProperty (ScreenPtr pScreen,
1326706f2543Smrg			      RROutputPtr randr_output,
1327706f2543Smrg			      Atom property)
1328706f2543Smrg{
1329706f2543Smrg    xf86OutputPtr output = randr_output->devPrivate;
1330706f2543Smrg
1331706f2543Smrg    if (output->funcs->get_property == NULL)
1332706f2543Smrg	return TRUE;
1333706f2543Smrg
1334706f2543Smrg    /* Should be safe even w/o vtSema */
1335706f2543Smrg    return output->funcs->get_property(output, property);
1336706f2543Smrg}
1337706f2543Smrg
1338706f2543Smrgstatic Bool
1339706f2543Smrgxf86RandR12OutputValidateMode (ScreenPtr    pScreen,
1340706f2543Smrg			       RROutputPtr  randr_output,
1341706f2543Smrg			       RRModePtr    randr_mode)
1342706f2543Smrg{
1343706f2543Smrg    ScrnInfoPtr	    pScrn = xf86Screens[pScreen->myNum];
1344706f2543Smrg    xf86OutputPtr   output = randr_output->devPrivate;
1345706f2543Smrg    DisplayModeRec  mode;
1346706f2543Smrg
1347706f2543Smrg    xf86RandRModeConvert (pScrn, randr_mode, &mode);
1348706f2543Smrg    /*
1349706f2543Smrg     * This function may be called when vtSema is FALSE, so
1350706f2543Smrg     * the underlying function must either avoid touching the hardware
1351706f2543Smrg     * or return FALSE when vtSema is FALSE
1352706f2543Smrg     */
1353706f2543Smrg    if (output->funcs->mode_valid (output, &mode) != MODE_OK)
1354706f2543Smrg	return FALSE;
1355706f2543Smrg    return TRUE;
1356706f2543Smrg}
1357706f2543Smrg
1358706f2543Smrgstatic void
1359706f2543Smrgxf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
1360706f2543Smrg{
1361706f2543Smrg}
1362706f2543Smrg
1363706f2543Smrg/**
1364706f2543Smrg * Given a list of xf86 modes and a RandR Output object, construct
1365706f2543Smrg * RandR modes and assign them to the output
1366706f2543Smrg */
1367706f2543Smrgstatic Bool
1368706f2543Smrgxf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes)
1369706f2543Smrg{
1370706f2543Smrg    DisplayModePtr  mode;
1371706f2543Smrg    RRModePtr	    *rrmodes = NULL;
1372706f2543Smrg    int		    nmode = 0;
1373706f2543Smrg    int		    npreferred = 0;
1374706f2543Smrg    Bool	    ret = TRUE;
1375706f2543Smrg    int		    pref;
1376706f2543Smrg
1377706f2543Smrg    for (mode = modes; mode; mode = mode->next)
1378706f2543Smrg	nmode++;
1379706f2543Smrg
1380706f2543Smrg    if (nmode) {
1381706f2543Smrg	rrmodes = malloc(nmode * sizeof (RRModePtr));
1382706f2543Smrg
1383706f2543Smrg	if (!rrmodes)
1384706f2543Smrg	    return FALSE;
1385706f2543Smrg	nmode = 0;
1386706f2543Smrg
1387706f2543Smrg	for (pref = 1; pref >= 0; pref--) {
1388706f2543Smrg	    for (mode = modes; mode; mode = mode->next) {
1389706f2543Smrg		if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
1390706f2543Smrg		    xRRModeInfo		modeInfo;
1391706f2543Smrg		    RRModePtr		rrmode;
1392706f2543Smrg
1393706f2543Smrg		    modeInfo.nameLength = strlen (mode->name);
1394706f2543Smrg		    modeInfo.width = mode->HDisplay;
1395706f2543Smrg		    modeInfo.dotClock = mode->Clock * 1000;
1396706f2543Smrg		    modeInfo.hSyncStart = mode->HSyncStart;
1397706f2543Smrg		    modeInfo.hSyncEnd = mode->HSyncEnd;
1398706f2543Smrg		    modeInfo.hTotal = mode->HTotal;
1399706f2543Smrg		    modeInfo.hSkew = mode->HSkew;
1400706f2543Smrg
1401706f2543Smrg		    modeInfo.height = mode->VDisplay;
1402706f2543Smrg		    modeInfo.vSyncStart = mode->VSyncStart;
1403706f2543Smrg		    modeInfo.vSyncEnd = mode->VSyncEnd;
1404706f2543Smrg		    modeInfo.vTotal = mode->VTotal;
1405706f2543Smrg		    modeInfo.modeFlags = mode->Flags;
1406706f2543Smrg
1407706f2543Smrg		    rrmode = RRModeGet (&modeInfo, mode->name);
1408706f2543Smrg		    if (rrmode) {
1409706f2543Smrg			rrmodes[nmode++] = rrmode;
1410706f2543Smrg			npreferred += pref;
1411706f2543Smrg		    }
1412706f2543Smrg		}
1413706f2543Smrg	    }
1414706f2543Smrg	}
1415706f2543Smrg    }
1416706f2543Smrg
1417706f2543Smrg    ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred);
1418706f2543Smrg    free(rrmodes);
1419706f2543Smrg    return ret;
1420706f2543Smrg}
1421706f2543Smrg
1422706f2543Smrg/*
1423706f2543Smrg * Mirror the current mode configuration to RandR
1424706f2543Smrg */
1425706f2543Smrgstatic Bool
1426706f2543Smrgxf86RandR12SetInfo12 (ScreenPtr pScreen)
1427706f2543Smrg{
1428706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1429706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1430706f2543Smrg    RROutputPtr		*clones;
1431706f2543Smrg    RRCrtcPtr		*crtcs;
1432706f2543Smrg    int			ncrtc;
1433706f2543Smrg    int			o, c, l;
1434706f2543Smrg    RRCrtcPtr		randr_crtc;
1435706f2543Smrg    int			nclone;
1436706f2543Smrg
1437706f2543Smrg    clones = malloc(config->num_output * sizeof (RROutputPtr));
1438706f2543Smrg    crtcs = malloc(config->num_crtc * sizeof (RRCrtcPtr));
1439706f2543Smrg    for (o = 0; o < config->num_output; o++)
1440706f2543Smrg    {
1441706f2543Smrg	xf86OutputPtr	output = config->output[o];
1442706f2543Smrg
1443706f2543Smrg	ncrtc = 0;
1444706f2543Smrg	for (c = 0; c < config->num_crtc; c++)
1445706f2543Smrg	    if (output->possible_crtcs & (1 << c))
1446706f2543Smrg		crtcs[ncrtc++] = config->crtc[c]->randr_crtc;
1447706f2543Smrg
1448706f2543Smrg	if (output->crtc)
1449706f2543Smrg	    randr_crtc = output->crtc->randr_crtc;
1450706f2543Smrg	else
1451706f2543Smrg	    randr_crtc = NULL;
1452706f2543Smrg
1453706f2543Smrg	if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc))
1454706f2543Smrg	{
1455706f2543Smrg	    free(crtcs);
1456706f2543Smrg	    free(clones);
1457706f2543Smrg	    return FALSE;
1458706f2543Smrg	}
1459706f2543Smrg
1460706f2543Smrg	RROutputSetPhysicalSize(output->randr_output,
1461706f2543Smrg				output->mm_width,
1462706f2543Smrg				output->mm_height);
1463706f2543Smrg	xf86RROutputSetModes (output->randr_output, output->probed_modes);
1464706f2543Smrg
1465706f2543Smrg	switch (output->status) {
1466706f2543Smrg	case XF86OutputStatusConnected:
1467706f2543Smrg	    RROutputSetConnection (output->randr_output, RR_Connected);
1468706f2543Smrg	    break;
1469706f2543Smrg	case XF86OutputStatusDisconnected:
1470706f2543Smrg	    RROutputSetConnection (output->randr_output, RR_Disconnected);
1471706f2543Smrg	    break;
1472706f2543Smrg	case XF86OutputStatusUnknown:
1473706f2543Smrg	    RROutputSetConnection (output->randr_output, RR_UnknownConnection);
1474706f2543Smrg	    break;
1475706f2543Smrg	}
1476706f2543Smrg
1477706f2543Smrg	RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order);
1478706f2543Smrg
1479706f2543Smrg	/*
1480706f2543Smrg	 * Valid clones
1481706f2543Smrg	 */
1482706f2543Smrg	nclone = 0;
1483706f2543Smrg	for (l = 0; l < config->num_output; l++)
1484706f2543Smrg	{
1485706f2543Smrg	    xf86OutputPtr	    clone = config->output[l];
1486706f2543Smrg
1487706f2543Smrg	    if (l != o && (output->possible_clones & (1 << l)))
1488706f2543Smrg		clones[nclone++] = clone->randr_output;
1489706f2543Smrg	}
1490706f2543Smrg	if (!RROutputSetClones (output->randr_output, clones, nclone))
1491706f2543Smrg	{
1492706f2543Smrg	    free(crtcs);
1493706f2543Smrg	    free(clones);
1494706f2543Smrg	    return FALSE;
1495706f2543Smrg	}
1496706f2543Smrg    }
1497706f2543Smrg    free(crtcs);
1498706f2543Smrg    free(clones);
1499706f2543Smrg    return TRUE;
1500706f2543Smrg}
1501706f2543Smrg
1502706f2543Smrg
1503706f2543Smrg
1504706f2543Smrg/*
1505706f2543Smrg * Query the hardware for the current state, then mirror
1506706f2543Smrg * that to RandR
1507706f2543Smrg */
1508706f2543Smrgstatic Bool
1509706f2543Smrgxf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
1510706f2543Smrg{
1511706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1512706f2543Smrg
1513706f2543Smrg    if (!pScrn->vtSema)
1514706f2543Smrg	return TRUE;
1515706f2543Smrg    xf86ProbeOutputModes (pScrn, 0, 0);
1516706f2543Smrg    xf86SetScrnInfoModes (pScrn);
1517706f2543Smrg    return xf86RandR12SetInfo12 (pScreen);
1518706f2543Smrg}
1519706f2543Smrg
1520706f2543Smrgstatic Bool
1521706f2543Smrgxf86RandR12CreateObjects12 (ScreenPtr pScreen)
1522706f2543Smrg{
1523706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1524706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1525706f2543Smrg    int			c;
1526706f2543Smrg    int			o;
1527706f2543Smrg
1528706f2543Smrg    if (!RRInit ())
1529706f2543Smrg	return FALSE;
1530706f2543Smrg
1531706f2543Smrg    /*
1532706f2543Smrg     * Configure crtcs
1533706f2543Smrg     */
1534706f2543Smrg    for (c = 0; c < config->num_crtc; c++)
1535706f2543Smrg    {
1536706f2543Smrg	xf86CrtcPtr    crtc = config->crtc[c];
1537706f2543Smrg
1538706f2543Smrg	crtc->randr_crtc = RRCrtcCreate (pScreen, crtc);
1539706f2543Smrg	RRCrtcGammaSetSize (crtc->randr_crtc, 256);
1540706f2543Smrg    }
1541706f2543Smrg    /*
1542706f2543Smrg     * Configure outputs
1543706f2543Smrg     */
1544706f2543Smrg    for (o = 0; o < config->num_output; o++)
1545706f2543Smrg    {
1546706f2543Smrg	xf86OutputPtr	output = config->output[o];
1547706f2543Smrg
1548706f2543Smrg	output->randr_output = RROutputCreate (pScreen, output->name,
1549706f2543Smrg					       strlen (output->name),
1550706f2543Smrg					       output);
1551706f2543Smrg
1552706f2543Smrg	if (output->funcs->create_resources != NULL)
1553706f2543Smrg	    output->funcs->create_resources(output);
1554706f2543Smrg	RRPostPendingProperties (output->randr_output);
1555706f2543Smrg    }
1556706f2543Smrg    return TRUE;
1557706f2543Smrg}
1558706f2543Smrg
1559706f2543Smrgstatic Bool
1560706f2543Smrgxf86RandR12CreateScreenResources12 (ScreenPtr pScreen)
1561706f2543Smrg{
1562706f2543Smrg    int			c;
1563706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1564706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1565706f2543Smrg
1566706f2543Smrg    if (xf86RandR12Key == NULL)
1567706f2543Smrg	return TRUE;
1568706f2543Smrg
1569706f2543Smrg    for (c = 0; c < config->num_crtc; c++)
1570706f2543Smrg        xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
1571706f2543Smrg
1572706f2543Smrg    RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight,
1573706f2543Smrg			  config->maxWidth, config->maxHeight);
1574706f2543Smrg    return TRUE;
1575706f2543Smrg}
1576706f2543Smrg
1577706f2543Smrg/*
1578706f2543Smrg * Something happened within the screen configuration due
1579706f2543Smrg * to DGA, VidMode or hot key. Tell RandR
1580706f2543Smrg */
1581706f2543Smrg
1582706f2543Smrgvoid
1583706f2543Smrgxf86RandR12TellChanged (ScreenPtr pScreen)
1584706f2543Smrg{
1585706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1586706f2543Smrg    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1587706f2543Smrg    int			c;
1588706f2543Smrg
1589706f2543Smrg    if (xf86RandR12Key == NULL)
1590706f2543Smrg	return;
1591706f2543Smrg
1592706f2543Smrg    xf86RandR12SetInfo12 (pScreen);
1593706f2543Smrg    for (c = 0; c < config->num_crtc; c++)
1594706f2543Smrg	xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
1595706f2543Smrg
1596706f2543Smrg    RRTellChanged (pScreen);
1597706f2543Smrg}
1598706f2543Smrg
1599706f2543Smrgstatic void
1600706f2543Smrgxf86RandR12PointerMoved (int scrnIndex, int x, int y)
1601706f2543Smrg{
1602706f2543Smrg    ScreenPtr		pScreen = screenInfo.screens[scrnIndex];
1603706f2543Smrg    ScrnInfoPtr		pScrn   = XF86SCRNINFO(pScreen);
1604706f2543Smrg    xf86CrtcConfigPtr	config  = XF86_CRTC_CONFIG_PTR(pScrn);
1605706f2543Smrg    XF86RandRInfoPtr	randrp  = XF86RANDRINFO(pScreen);
1606706f2543Smrg    int c;
1607706f2543Smrg
1608706f2543Smrg    randrp->pointerX = x;
1609706f2543Smrg    randrp->pointerY = y;
1610706f2543Smrg    for (c = 0; c < config->num_crtc; c++)
1611706f2543Smrg	xf86RandR13Pan (config->crtc[c], x, y);
1612706f2543Smrg}
1613706f2543Smrg
1614706f2543Smrgstatic Bool
1615706f2543Smrgxf86RandR13GetPanning (ScreenPtr           pScreen,
1616706f2543Smrg		       RRCrtcPtr           randr_crtc,
1617706f2543Smrg		       BoxPtr              totalArea,
1618706f2543Smrg		       BoxPtr              trackingArea,
1619706f2543Smrg		       INT16               *border)
1620706f2543Smrg{
1621706f2543Smrg    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
1622706f2543Smrg
1623706f2543Smrg    if (crtc->version < 2)
1624706f2543Smrg	return FALSE;
1625706f2543Smrg    if (totalArea)
1626706f2543Smrg	memcpy (totalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
1627706f2543Smrg    if (trackingArea)
1628706f2543Smrg	memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
1629706f2543Smrg    if (border)
1630706f2543Smrg	memcpy (border,        crtc->panningBorder,       4*sizeof(INT16));
1631706f2543Smrg
1632706f2543Smrg    return TRUE;
1633706f2543Smrg}
1634706f2543Smrg
1635706f2543Smrgstatic Bool
1636706f2543Smrgxf86RandR13SetPanning (ScreenPtr           pScreen,
1637706f2543Smrg		       RRCrtcPtr           randr_crtc,
1638706f2543Smrg		       BoxPtr              totalArea,
1639706f2543Smrg		       BoxPtr              trackingArea,
1640706f2543Smrg		       INT16               *border)
1641706f2543Smrg{
1642706f2543Smrg    XF86RandRInfoPtr	randrp  = XF86RANDRINFO(pScreen);
1643706f2543Smrg    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
1644706f2543Smrg    BoxRec		oldTotalArea;
1645706f2543Smrg    BoxRec		oldTrackingArea;
1646706f2543Smrg    INT16		oldBorder[4];
1647706f2543Smrg
1648706f2543Smrg
1649706f2543Smrg    if (crtc->version < 2)
1650706f2543Smrg	return FALSE;
1651706f2543Smrg
1652706f2543Smrg    memcpy (&oldTotalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
1653706f2543Smrg    memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
1654706f2543Smrg    memcpy (oldBorder,         crtc->panningBorder,       4*sizeof(INT16));
1655706f2543Smrg
1656706f2543Smrg    if (totalArea)
1657706f2543Smrg	memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec));
1658706f2543Smrg    if (trackingArea)
1659706f2543Smrg	memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec));
1660706f2543Smrg    if (border)
1661706f2543Smrg	memcpy (crtc->panningBorder, border, 4*sizeof(INT16));
1662706f2543Smrg
1663706f2543Smrg    if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) {
1664706f2543Smrg	xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
1665706f2543Smrg	return TRUE;
1666706f2543Smrg    } else {
1667706f2543Smrg	/* Restore old settings */
1668706f2543Smrg	memcpy (&crtc->panningTotalArea,    &oldTotalArea,    sizeof(BoxRec));
1669706f2543Smrg	memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec));
1670706f2543Smrg	memcpy (crtc->panningBorder,         oldBorder,       4*sizeof(INT16));
1671706f2543Smrg	return FALSE;
1672706f2543Smrg    }
1673706f2543Smrg}
1674706f2543Smrg
1675706f2543Smrg/*
1676706f2543Smrg * Compatibility with XF86VidMode's gamma changer.  This necessarily clobbers
1677706f2543Smrg * any per-crtc setup.  You asked for it...
1678706f2543Smrg */
1679706f2543Smrg
1680706f2543Smrgstatic void
1681706f2543Smrggamma_to_ramp(float gamma, CARD16 *ramp, int size)
1682706f2543Smrg{
1683706f2543Smrg    int i;
1684706f2543Smrg
1685706f2543Smrg    for (i = 0; i < size; i++) {
1686706f2543Smrg	if (gamma == 1.0)
1687706f2543Smrg	    ramp[i] = i << 8;
1688706f2543Smrg	else
1689706f2543Smrg	    ramp[i] = (CARD16)(pow((double)i / (double)(size - 1), 1. / gamma)
1690706f2543Smrg			       * (double)(size - 1) * 256);
1691706f2543Smrg    }
1692706f2543Smrg}
1693706f2543Smrg
1694706f2543Smrgstatic int
1695706f2543Smrgxf86RandR12ChangeGamma(int scrnIndex, Gamma gamma)
1696706f2543Smrg{
1697706f2543Smrg    CARD16 *points, *red, *green, *blue;
1698706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1699706f2543Smrg    RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn);
1700706f2543Smrg    int size;
1701706f2543Smrg
1702706f2543Smrg    if (!crtc)
1703706f2543Smrg	return Success;
1704706f2543Smrg
1705706f2543Smrg    size = max(0, crtc->gammaSize);
1706706f2543Smrg    if (!size)
1707706f2543Smrg	return Success;
1708706f2543Smrg
1709706f2543Smrg    points = calloc(size, 3 * sizeof(CARD16));
1710706f2543Smrg    if (!points)
1711706f2543Smrg	return BadAlloc;
1712706f2543Smrg
1713706f2543Smrg    red = points;
1714706f2543Smrg    green = points + size;
1715706f2543Smrg    blue = points + 2 * size;
1716706f2543Smrg
1717706f2543Smrg    gamma_to_ramp(gamma.red, red, size);
1718706f2543Smrg    gamma_to_ramp(gamma.green, green, size);
1719706f2543Smrg    gamma_to_ramp(gamma.blue, blue, size);
1720706f2543Smrg    RRCrtcGammaSet(crtc, red, green, blue);
1721706f2543Smrg
1722706f2543Smrg    free(points);
1723706f2543Smrg
1724706f2543Smrg    pScrn->gamma = gamma;
1725706f2543Smrg
1726706f2543Smrg    return Success;
1727706f2543Smrg}
1728706f2543Smrg
1729706f2543Smrgstatic Bool
1730706f2543Smrgxf86RandR12EnterVT (int screen_index, int flags)
1731706f2543Smrg{
1732706f2543Smrg    ScreenPtr        pScreen = screenInfo.screens[screen_index];
1733706f2543Smrg    ScrnInfoPtr	     pScrn = xf86Screens[screen_index];
1734706f2543Smrg    XF86RandRInfoPtr randrp  = XF86RANDRINFO(pScreen);
1735706f2543Smrg    rrScrPrivPtr     rp = rrGetScrPriv(pScreen);
1736706f2543Smrg    Bool	     ret;
1737706f2543Smrg
1738706f2543Smrg    if (randrp->orig_EnterVT) {
1739706f2543Smrg	pScrn->EnterVT = randrp->orig_EnterVT;
1740706f2543Smrg	ret = pScrn->EnterVT (screen_index, flags);
1741706f2543Smrg	randrp->orig_EnterVT = pScrn->EnterVT;
1742706f2543Smrg	pScrn->EnterVT = xf86RandR12EnterVT;
1743706f2543Smrg	if (!ret)
1744706f2543Smrg	    return FALSE;
1745706f2543Smrg    }
1746706f2543Smrg
1747706f2543Smrg    /* reload gamma */
1748706f2543Smrg    int i;
1749706f2543Smrg    for (i = 0; i < rp->numCrtcs; i++)
1750706f2543Smrg	xf86RandR12CrtcSetGamma(pScreen, rp->crtcs[i]);
1751706f2543Smrg
1752706f2543Smrg    return RRGetInfo (pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */
1753706f2543Smrg}
1754706f2543Smrg
1755706f2543Smrgstatic Bool
1756706f2543Smrgxf86RandR12Init12 (ScreenPtr pScreen)
1757706f2543Smrg{
1758706f2543Smrg    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1759706f2543Smrg    rrScrPrivPtr	rp = rrGetScrPriv(pScreen);
1760706f2543Smrg    XF86RandRInfoPtr	randrp  = XF86RANDRINFO(pScreen);
1761706f2543Smrg    int i;
1762706f2543Smrg
1763706f2543Smrg    rp->rrGetInfo = xf86RandR12GetInfo12;
1764706f2543Smrg    rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
1765706f2543Smrg    rp->rrCrtcSet = xf86RandR12CrtcSet;
1766706f2543Smrg    rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
1767706f2543Smrg    rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma;
1768706f2543Smrg    rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
1769706f2543Smrg    rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
1770706f2543Smrg#if RANDR_13_INTERFACE
1771706f2543Smrg    rp->rrOutputGetProperty = xf86RandR13OutputGetProperty;
1772706f2543Smrg    rp->rrGetPanning = xf86RandR13GetPanning;
1773706f2543Smrg    rp->rrSetPanning = xf86RandR13SetPanning;
1774706f2543Smrg#endif
1775706f2543Smrg    rp->rrModeDestroy = xf86RandR12ModeDestroy;
1776706f2543Smrg    rp->rrSetConfig = NULL;
1777706f2543Smrg    pScrn->PointerMoved = xf86RandR12PointerMoved;
1778706f2543Smrg    pScrn->ChangeGamma = xf86RandR12ChangeGamma;
1779706f2543Smrg
1780706f2543Smrg    randrp->orig_EnterVT = pScrn->EnterVT;
1781706f2543Smrg    pScrn->EnterVT = xf86RandR12EnterVT;
1782706f2543Smrg
1783706f2543Smrg    if (!xf86RandR12CreateObjects12 (pScreen))
1784706f2543Smrg	return FALSE;
1785706f2543Smrg
1786706f2543Smrg    /*
1787706f2543Smrg     * Configure output modes
1788706f2543Smrg     */
1789706f2543Smrg    if (!xf86RandR12SetInfo12 (pScreen))
1790706f2543Smrg	return FALSE;
1791706f2543Smrg    for (i = 0; i < rp->numCrtcs; i++) {
1792706f2543Smrg	xf86RandR12CrtcGetGamma(pScreen, rp->crtcs[i]);
1793706f2543Smrg    }
1794706f2543Smrg    return TRUE;
1795706f2543Smrg}
1796706f2543Smrg
1797706f2543Smrg#endif
1798706f2543Smrg
1799706f2543SmrgBool
1800706f2543Smrgxf86RandR12PreInit (ScrnInfoPtr pScrn)
1801706f2543Smrg{
1802706f2543Smrg    return TRUE;
1803706f2543Smrg}
1804