1 /*
2  * Copyright © 2006 Keith Packard
3  * Copyright © 2008 Red Hat, Inc.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23 
24 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
26 #endif
27 
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdio.h>
31 
32 #include "xf86.h"
33 #include "xf86DDC.h"
34 #include "xf86Crtc.h"
35 #include "xf86Modes.h"
36 #include "xf86Priv.h"
37 #include "xf86RandR12.h"
38 #include "X11/extensions/render.h"
39 #include "X11/extensions/dpmsconst.h"
40 #include "X11/Xatom.h"
41 #include "picturestr.h"
42 
43 #ifdef XV
44 #include "xf86xv.h"
45 #endif
46 
47 #define NO_OUTPUT_DEFAULT_WIDTH 1024
48 #define NO_OUTPUT_DEFAULT_HEIGHT 768
49 /*
50  * Initialize xf86CrtcConfig structure
51  */
52 
53 int xf86CrtcConfigPrivateIndex = -1;
54 
55 void
xf86CrtcConfigInit(ScrnInfoPtr scrn,const xf86CrtcConfigFuncsRec * funcs)56 xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs)
57 {
58     xf86CrtcConfigPtr config;
59 
60     if (xf86CrtcConfigPrivateIndex == -1)
61         xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
62     config = xnfcalloc(1, sizeof(xf86CrtcConfigRec));
63 
64     config->funcs = funcs;
65     config->compat_output = -1;
66 
67     scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config;
68 }
69 
70 void
xf86CrtcSetSizeRange(ScrnInfoPtr scrn,int minWidth,int minHeight,int maxWidth,int maxHeight)71 xf86CrtcSetSizeRange(ScrnInfoPtr scrn,
72                      int minWidth, int minHeight, int maxWidth, int maxHeight)
73 {
74     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
75 
76     config->minWidth = minWidth;
77     config->minHeight = minHeight;
78     config->maxWidth = maxWidth;
79     config->maxHeight = maxHeight;
80 }
81 
82 /*
83  * Crtc functions
84  */
85 xf86CrtcPtr
xf86CrtcCreate(ScrnInfoPtr scrn,const xf86CrtcFuncsRec * funcs)86 xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs)
87 {
88     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
89     xf86CrtcPtr crtc, *crtcs;
90 
91     crtc = calloc(sizeof(xf86CrtcRec), 1);
92     if (!crtc)
93         return NULL;
94     crtc->version = XF86_CRTC_VERSION;
95     crtc->scrn = scrn;
96     crtc->funcs = funcs;
97 #ifdef RANDR_12_INTERFACE
98     crtc->randr_crtc = NULL;
99 #endif
100     crtc->rotation = RR_Rotate_0;
101     crtc->desiredRotation = RR_Rotate_0;
102     pixman_transform_init_identity(&crtc->crtc_to_framebuffer);
103     pixman_f_transform_init_identity(&crtc->f_crtc_to_framebuffer);
104     pixman_f_transform_init_identity(&crtc->f_framebuffer_to_crtc);
105     crtc->filter = NULL;
106     crtc->params = NULL;
107     crtc->nparams = 0;
108     crtc->filter_width = 0;
109     crtc->filter_height = 0;
110     crtc->transform_in_use = FALSE;
111     crtc->transformPresent = FALSE;
112     crtc->desiredTransformPresent = FALSE;
113     memset(&crtc->bounds, '\0', sizeof(crtc->bounds));
114 
115     /* Preallocate gamma at a sensible size. */
116     crtc->gamma_size = 256;
117     crtc->gamma_red = xallocarray(crtc->gamma_size, 3 * sizeof(CARD16));
118     if (!crtc->gamma_red) {
119         free(crtc);
120         return NULL;
121     }
122     crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
123     crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
124 
125     if (xf86_config->crtc)
126         crtcs = reallocarray(xf86_config->crtc,
127                              xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
128     else
129         crtcs = xallocarray(xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr));
130     if (!crtcs) {
131         free(crtc->gamma_red);
132         free(crtc);
133         return NULL;
134     }
135     xf86_config->crtc = crtcs;
136     xf86_config->crtc[xf86_config->num_crtc++] = crtc;
137     return crtc;
138 }
139 
140 void
xf86CrtcDestroy(xf86CrtcPtr crtc)141 xf86CrtcDestroy(xf86CrtcPtr crtc)
142 {
143     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
144     int c;
145 
146     (*crtc->funcs->destroy) (crtc);
147     for (c = 0; c < xf86_config->num_crtc; c++)
148         if (xf86_config->crtc[c] == crtc) {
149             memmove(&xf86_config->crtc[c],
150                     &xf86_config->crtc[c + 1],
151                     ((xf86_config->num_crtc - (c + 1)) * sizeof(void *)));
152             xf86_config->num_crtc--;
153             break;
154         }
155     free(crtc->params);
156     free(crtc->gamma_red);
157     free(crtc);
158 }
159 
160 /**
161  * Return whether any outputs are connected to the specified pipe
162  */
163 
164 Bool
xf86CrtcInUse(xf86CrtcPtr crtc)165 xf86CrtcInUse(xf86CrtcPtr crtc)
166 {
167     ScrnInfoPtr pScrn = crtc->scrn;
168     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
169     int o;
170 
171     for (o = 0; o < xf86_config->num_output; o++)
172         if (xf86_config->output[o]->crtc == crtc)
173             return TRUE;
174     return FALSE;
175 }
176 
177 /**
178  * Return whether the crtc is leased by a client
179  */
180 
181 static Bool
xf86CrtcIsLeased(xf86CrtcPtr crtc)182 xf86CrtcIsLeased(xf86CrtcPtr crtc)
183 {
184     /* If the DIX structure hasn't been created, it can't have been leased */
185     if (!crtc->randr_crtc)
186         return FALSE;
187     return RRCrtcIsLeased(crtc->randr_crtc);
188 }
189 
190 /**
191  * Return whether the output is leased by a client
192  */
193 
194 static Bool
xf86OutputIsLeased(xf86OutputPtr output)195 xf86OutputIsLeased(xf86OutputPtr output)
196 {
197     /* If the DIX structure hasn't been created, it can't have been leased */
198     if (!output->randr_output)
199         return FALSE;
200     return RROutputIsLeased(output->randr_output);
201 }
202 
203 void
xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen)204 xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen)
205 {
206     int subpixel_order = SubPixelUnknown;
207     Bool has_none = FALSE;
208     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
209     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
210     int icrtc, o;
211 
212     for (icrtc = 0; icrtc < xf86_config->num_crtc; icrtc++) {
213         xf86CrtcPtr crtc = xf86_config->crtc[icrtc];
214 
215         for (o = 0; o < xf86_config->num_output; o++) {
216             xf86OutputPtr output = xf86_config->output[o];
217 
218             if (output->crtc == crtc) {
219                 switch (output->subpixel_order) {
220                 case SubPixelNone:
221                     has_none = TRUE;
222                     break;
223                 case SubPixelUnknown:
224                     break;
225                 default:
226                     subpixel_order = output->subpixel_order;
227                     break;
228                 }
229             }
230             if (subpixel_order != SubPixelUnknown)
231                 break;
232         }
233         if (subpixel_order != SubPixelUnknown) {
234             static const int circle[4] = {
235                 SubPixelHorizontalRGB,
236                 SubPixelVerticalRGB,
237                 SubPixelHorizontalBGR,
238                 SubPixelVerticalBGR,
239             };
240             int rotate;
241             int sc;
242 
243             for (rotate = 0; rotate < 4; rotate++)
244                 if (crtc->rotation & (1 << rotate))
245                     break;
246             for (sc = 0; sc < 4; sc++)
247                 if (circle[sc] == subpixel_order)
248                     break;
249             sc = (sc + rotate) & 0x3;
250             if ((crtc->rotation & RR_Reflect_X) && !(sc & 1))
251                 sc ^= 2;
252             if ((crtc->rotation & RR_Reflect_Y) && (sc & 1))
253                 sc ^= 2;
254             subpixel_order = circle[sc];
255             break;
256         }
257     }
258     if (subpixel_order == SubPixelUnknown && has_none)
259         subpixel_order = SubPixelNone;
260     PictureSetSubpixelOrder(pScreen, subpixel_order);
261 }
262 
263 /**
264  * Sets the given video mode on the given crtc
265  */
266 Bool
xf86CrtcSetModeTransform(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,RRTransformPtr transform,int x,int y)267 xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode,
268                          Rotation rotation, RRTransformPtr transform, int x,
269                          int y)
270 {
271     ScrnInfoPtr scrn = crtc->scrn;
272     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
273     int i;
274     Bool ret = FALSE;
275     Bool didLock = FALSE;
276     DisplayModePtr adjusted_mode;
277     DisplayModeRec saved_mode;
278     int saved_x, saved_y;
279     Rotation saved_rotation;
280     RRTransformRec saved_transform;
281     Bool saved_transform_present;
282 
283     crtc->enabled = xf86CrtcInUse(crtc) && !xf86CrtcIsLeased(crtc);
284 
285     /* We only hit this if someone explicitly sends a "disabled" modeset. */
286     if (!crtc->enabled) {
287         /* Check everything for stuff that should be off. */
288         xf86DisableUnusedFunctions(scrn);
289         return TRUE;
290     }
291 
292     adjusted_mode = xf86DuplicateMode(mode);
293 
294     saved_mode = crtc->mode;
295     saved_x = crtc->x;
296     saved_y = crtc->y;
297     saved_rotation = crtc->rotation;
298     if (crtc->transformPresent) {
299         RRTransformInit(&saved_transform);
300         RRTransformCopy(&saved_transform, &crtc->transform);
301     }
302     saved_transform_present = crtc->transformPresent;
303 
304     /* Update crtc values up front so the driver can rely on them for mode
305      * setting.
306      */
307     crtc->mode = *mode;
308     crtc->x = x;
309     crtc->y = y;
310     crtc->rotation = rotation;
311     if (transform) {
312         RRTransformCopy(&crtc->transform, transform);
313         crtc->transformPresent = TRUE;
314     }
315     else
316         crtc->transformPresent = FALSE;
317 
318     if (crtc->funcs->set_mode_major) {
319         ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y);
320         goto done;
321     }
322 
323     didLock = crtc->funcs->lock(crtc);
324     /* Pass our mode to the outputs and the CRTC to give them a chance to
325      * adjust it according to limitations or output properties, and also
326      * a chance to reject the mode entirely.
327      */
328     for (i = 0; i < xf86_config->num_output; i++) {
329         xf86OutputPtr output = xf86_config->output[i];
330 
331         if (output->crtc != crtc)
332             continue;
333 
334         if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
335             goto done;
336         }
337     }
338 
339     if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) {
340         goto done;
341     }
342 
343     if (!xf86CrtcRotate(crtc))
344         goto done;
345 
346     /* Prepare the outputs and CRTCs before setting the mode. */
347     for (i = 0; i < xf86_config->num_output; i++) {
348         xf86OutputPtr output = xf86_config->output[i];
349 
350         if (output->crtc != crtc)
351             continue;
352 
353         /* Disable the output as the first thing we do. */
354         output->funcs->prepare(output);
355     }
356 
357     crtc->funcs->prepare(crtc);
358 
359     /* Set up the DPLL and any output state that needs to adjust or depend
360      * on the DPLL.
361      */
362     crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y);
363     for (i = 0; i < xf86_config->num_output; i++) {
364         xf86OutputPtr output = xf86_config->output[i];
365 
366         if (output->crtc == crtc)
367             output->funcs->mode_set(output, mode, adjusted_mode);
368     }
369 
370     /* Only upload when needed, to avoid unneeded delays. */
371     if (!crtc->active && crtc->funcs->gamma_set)
372         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
373                                crtc->gamma_blue, crtc->gamma_size);
374 
375     /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
376     crtc->funcs->commit(crtc);
377     for (i = 0; i < xf86_config->num_output; i++) {
378         xf86OutputPtr output = xf86_config->output[i];
379 
380         if (output->crtc == crtc)
381             output->funcs->commit(output);
382     }
383 
384     ret = TRUE;
385 
386  done:
387     if (ret) {
388         crtc->active = TRUE;
389         if (scrn->pScreen)
390             xf86CrtcSetScreenSubpixelOrder(scrn->pScreen);
391         if (scrn->ModeSet)
392             scrn->ModeSet(scrn);
393 
394         /* Make sure the HW cursor is hidden if it's supposed to be, in case
395          * it was hidden while the CRTC was disabled
396          */
397         if (!xf86_config->cursor_on)
398             xf86_hide_cursors(scrn);
399     }
400     else {
401         crtc->x = saved_x;
402         crtc->y = saved_y;
403         crtc->rotation = saved_rotation;
404         crtc->mode = saved_mode;
405         if (saved_transform_present)
406             RRTransformCopy(&crtc->transform, &saved_transform);
407         crtc->transformPresent = saved_transform_present;
408     }
409 
410     free((void *) adjusted_mode->name);
411     free(adjusted_mode);
412 
413     if (didLock)
414         crtc->funcs->unlock(crtc);
415 
416     return ret;
417 }
418 
419 /**
420  * Sets the given video mode on the given crtc, but without providing
421  * a transform
422  */
423 Bool
xf86CrtcSetMode(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)424 xf86CrtcSetMode(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation,
425                 int x, int y)
426 {
427     return xf86CrtcSetModeTransform(crtc, mode, rotation, NULL, x, y);
428 }
429 
430 /**
431  * Pans the screen, does not change the mode
432  */
433 void
xf86CrtcSetOrigin(xf86CrtcPtr crtc,int x,int y)434 xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y)
435 {
436     ScrnInfoPtr scrn = crtc->scrn;
437 
438     crtc->x = x;
439     crtc->y = y;
440 
441     if (xf86CrtcIsLeased(crtc))
442         return;
443 
444     if (crtc->funcs->set_origin) {
445         if (!xf86CrtcRotate(crtc))
446             return;
447         crtc->funcs->set_origin(crtc, x, y);
448         if (scrn->ModeSet)
449             scrn->ModeSet(scrn);
450     }
451     else
452         xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, x, y);
453 }
454 
455 /*
456  * Output functions
457  */
458 
459 extern XF86ConfigPtr xf86configptr;
460 
461 typedef enum {
462     OPTION_PREFERRED_MODE,
463     OPTION_ZOOM_MODES,
464     OPTION_POSITION,
465     OPTION_BELOW,
466     OPTION_RIGHT_OF,
467     OPTION_ABOVE,
468     OPTION_LEFT_OF,
469     OPTION_ENABLE,
470     OPTION_DISABLE,
471     OPTION_MIN_CLOCK,
472     OPTION_MAX_CLOCK,
473     OPTION_IGNORE,
474     OPTION_ROTATE,
475     OPTION_PANNING,
476     OPTION_PRIMARY,
477     OPTION_DEFAULT_MODES,
478 } OutputOpts;
479 
480 static OptionInfoRec xf86OutputOptions[] = {
481     {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE},
482     {OPTION_ZOOM_MODES, "ZoomModes", OPTV_STRING, {0}, FALSE },
483     {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE},
484     {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE},
485     {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE},
486     {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE},
487     {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE},
488     {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE},
489     {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE},
490     {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE},
491     {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE},
492     {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE},
493     {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE},
494     {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE},
495     {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE},
496     {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE},
497     {-1, NULL, OPTV_NONE, {0}, FALSE},
498 };
499 
500 enum {
501     OPTION_MODEDEBUG,
502     OPTION_PREFER_CLONEMODE,
503     OPTION_NO_OUTPUT_INITIAL_SIZE,
504 };
505 
506 static OptionInfoRec xf86DeviceOptions[] = {
507     {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE},
508     {OPTION_PREFER_CLONEMODE, "PreferCloneMode", OPTV_BOOLEAN, {0}, FALSE},
509     {OPTION_NO_OUTPUT_INITIAL_SIZE, "NoOutputInitialSize", OPTV_STRING, {0}, FALSE},
510     {-1, NULL, OPTV_NONE, {0}, FALSE},
511 };
512 
513 static void
xf86OutputSetMonitor(xf86OutputPtr output)514 xf86OutputSetMonitor(xf86OutputPtr output)
515 {
516     char *option_name;
517     const char *monitor;
518 
519     if (!output->name)
520         return;
521 
522     free(output->options);
523 
524     output->options = xnfalloc(sizeof(xf86OutputOptions));
525     memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions));
526 
527     XNFasprintf(&option_name, "monitor-%s", output->name);
528     monitor = xf86findOptionValue(output->scrn->options, option_name);
529     if (!monitor)
530         monitor = output->name;
531     else
532         xf86MarkOptionUsedByName(output->scrn->options, option_name);
533     free(option_name);
534     output->conf_monitor = xf86findMonitor(monitor,
535                                            xf86configptr->conf_monitor_lst);
536     /*
537      * Find the monitor section of the screen and use that
538      */
539     if (!output->conf_monitor && output->use_screen_monitor)
540         output->conf_monitor = xf86findMonitor(output->scrn->monitor->id,
541                                                xf86configptr->conf_monitor_lst);
542     if (output->conf_monitor) {
543         xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
544                    "Output %s using monitor section %s\n",
545                    output->name, output->conf_monitor->mon_identifier);
546         xf86ProcessOptions(output->scrn->scrnIndex,
547                            output->conf_monitor->mon_option_lst,
548                            output->options);
549     }
550     else
551         xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
552                    "Output %s has no monitor section\n", output->name);
553 }
554 
555 Bool
xf86OutputForceEnabled(xf86OutputPtr output)556 xf86OutputForceEnabled(xf86OutputPtr output)
557 {
558     Bool enable;
559 
560     if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable)
561         return TRUE;
562     return FALSE;
563 }
564 
565 static Bool
xf86OutputEnabled(xf86OutputPtr output,Bool strict)566 xf86OutputEnabled(xf86OutputPtr output, Bool strict)
567 {
568     Bool enable, disable;
569 
570     /* check to see if this output was enabled in the config file */
571     if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable) {
572         xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
573                    "Output %s enabled by config file\n", output->name);
574         return TRUE;
575     }
576     /* or if this output was disabled in the config file */
577     if (xf86GetOptValBool(output->options, OPTION_DISABLE, &disable) && disable) {
578         xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
579                    "Output %s disabled by config file\n", output->name);
580         return FALSE;
581     }
582 
583     /* If not, try to only light up the ones we know are connected which are supposed to be on the desktop */
584     if (strict) {
585         enable = output->status == XF86OutputStatusConnected && !output->non_desktop;
586     }
587     /* But if that fails, try to light up even outputs we're unsure of */
588     else {
589         enable = output->status != XF86OutputStatusDisconnected;
590     }
591 
592     xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
593                "Output %s %sconnected\n", output->name, enable ? "" : "dis");
594     return enable;
595 }
596 
597 static Bool
xf86OutputIgnored(xf86OutputPtr output)598 xf86OutputIgnored(xf86OutputPtr output)
599 {
600     return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE);
601 }
602 
603 static const char *direction[4] = {
604     "normal",
605     "left",
606     "inverted",
607     "right"
608 };
609 
610 static Rotation
xf86OutputInitialRotation(xf86OutputPtr output)611 xf86OutputInitialRotation(xf86OutputPtr output)
612 {
613     const char *rotate_name = xf86GetOptValString(output->options,
614                                                   OPTION_ROTATE);
615     int i;
616 
617     if (!rotate_name) {
618         if (output->initial_rotation)
619             return output->initial_rotation;
620         return RR_Rotate_0;
621     }
622 
623     for (i = 0; i < 4; i++)
624         if (xf86nameCompare(direction[i], rotate_name) == 0)
625             return 1 << i;
626     return RR_Rotate_0;
627 }
628 
629 xf86OutputPtr
xf86OutputCreate(ScrnInfoPtr scrn,const xf86OutputFuncsRec * funcs,const char * name)630 xf86OutputCreate(ScrnInfoPtr scrn,
631                  const xf86OutputFuncsRec * funcs, const char *name)
632 {
633     xf86OutputPtr output, *outputs;
634     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
635     int len;
636     Bool primary;
637 
638     if (name)
639         len = strlen(name) + 1;
640     else
641         len = 0;
642 
643     output = calloc(sizeof(xf86OutputRec) + len, 1);
644     if (!output)
645         return NULL;
646     output->scrn = scrn;
647     output->funcs = funcs;
648     if (name) {
649         output->name = (char *) (output + 1);
650         strcpy(output->name, name);
651     }
652     output->subpixel_order = SubPixelUnknown;
653     /*
654      * Use the old per-screen monitor section for the first output
655      */
656     output->use_screen_monitor = (xf86_config->num_output == 0);
657 #ifdef RANDR_12_INTERFACE
658     output->randr_output = NULL;
659 #endif
660     if (name) {
661         xf86OutputSetMonitor(output);
662         if (xf86OutputIgnored(output)) {
663             free(output);
664             return FALSE;
665         }
666     }
667 
668     if (xf86_config->output)
669         outputs = reallocarray(xf86_config->output,
670                                xf86_config->num_output + 1,
671                                sizeof(xf86OutputPtr));
672     else
673         outputs = xallocarray(xf86_config->num_output + 1,
674                               sizeof(xf86OutputPtr));
675     if (!outputs) {
676         free(output);
677         return NULL;
678     }
679 
680     xf86_config->output = outputs;
681 
682     if (xf86GetOptValBool(output->options, OPTION_PRIMARY, &primary) && primary) {
683         memmove(xf86_config->output + 1, xf86_config->output,
684                 xf86_config->num_output * sizeof(xf86OutputPtr));
685         xf86_config->output[0] = output;
686     }
687     else {
688         xf86_config->output[xf86_config->num_output] = output;
689     }
690 
691     xf86_config->num_output++;
692 
693     return output;
694 }
695 
696 Bool
xf86OutputRename(xf86OutputPtr output,const char * name)697 xf86OutputRename(xf86OutputPtr output, const char *name)
698 {
699     char *newname = strdup(name);
700 
701     if (!newname)
702         return FALSE;           /* so sorry... */
703 
704     if (output->name && output->name != (char *) (output + 1))
705         free(output->name);
706     output->name = newname;
707     xf86OutputSetMonitor(output);
708     if (xf86OutputIgnored(output))
709         return FALSE;
710     return TRUE;
711 }
712 
713 void
xf86OutputUseScreenMonitor(xf86OutputPtr output,Bool use_screen_monitor)714 xf86OutputUseScreenMonitor(xf86OutputPtr output, Bool use_screen_monitor)
715 {
716     if (use_screen_monitor != output->use_screen_monitor) {
717         output->use_screen_monitor = use_screen_monitor;
718         xf86OutputSetMonitor(output);
719     }
720 }
721 
722 void
xf86OutputDestroy(xf86OutputPtr output)723 xf86OutputDestroy(xf86OutputPtr output)
724 {
725     ScrnInfoPtr scrn = output->scrn;
726     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
727     int o;
728 
729     (*output->funcs->destroy) (output);
730     while (output->probed_modes)
731         xf86DeleteMode(&output->probed_modes, output->probed_modes);
732     for (o = 0; o < xf86_config->num_output; o++)
733         if (xf86_config->output[o] == output) {
734             memmove(&xf86_config->output[o],
735                     &xf86_config->output[o + 1],
736                     ((xf86_config->num_output - (o + 1)) * sizeof(void *)));
737             xf86_config->num_output--;
738             break;
739         }
740     if (output->name && output->name != (char *) (output + 1))
741         free(output->name);
742     free(output);
743 }
744 
745 /*
746  * Called during CreateScreenResources to hook up RandR
747  */
748 static Bool
xf86CrtcCreateScreenResources(ScreenPtr screen)749 xf86CrtcCreateScreenResources(ScreenPtr screen)
750 {
751     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
752     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
753 
754     screen->CreateScreenResources = config->CreateScreenResources;
755 
756     if (!(*screen->CreateScreenResources) (screen))
757         return FALSE;
758 
759     if (!xf86RandR12CreateScreenResources(screen))
760         return FALSE;
761 
762     return TRUE;
763 }
764 
765 /*
766  * Clean up config on server reset
767  */
768 static Bool
xf86CrtcCloseScreen(ScreenPtr screen)769 xf86CrtcCloseScreen(ScreenPtr screen)
770 {
771     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
772     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
773     int o, c;
774 
775     /* The randr_output and randr_crtc pointers are already invalid as
776      * the DIX resources were freed when the associated resources were
777      * freed. Clear them now; referencing through them during the rest
778      * of the CloseScreen sequence will not end well.
779      */
780     for (o = 0; o < config->num_output; o++) {
781         xf86OutputPtr output = config->output[o];
782 
783         output->randr_output = NULL;
784     }
785     for (c = 0; c < config->num_crtc; c++) {
786         xf86CrtcPtr crtc = config->crtc[c];
787 
788         crtc->randr_crtc = NULL;
789     }
790 
791     screen->CloseScreen = config->CloseScreen;
792 
793     xf86RotateCloseScreen(screen);
794 
795     xf86RandR12CloseScreen(screen);
796 
797     screen->CloseScreen(screen);
798 
799     /* detach any providers */
800     if (config->randr_provider) {
801         RRProviderDestroy(config->randr_provider);
802         config->randr_provider = NULL;
803     }
804     return TRUE;
805 }
806 
807 /*
808  * Called at ScreenInit time to set up
809  */
810 #ifdef RANDR_13_INTERFACE
811 int
812 #else
813 Bool
814 #endif
xf86CrtcScreenInit(ScreenPtr screen)815 xf86CrtcScreenInit(ScreenPtr screen)
816 {
817     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
818     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
819     int c;
820 
821     /* Rotation */
822     xf86RandR12Init(screen);
823 
824     /* support all rotations if every crtc has the shadow alloc funcs */
825     for (c = 0; c < config->num_crtc; c++) {
826         xf86CrtcPtr crtc = config->crtc[c];
827 
828         if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create)
829             break;
830     }
831     if (c == config->num_crtc) {
832         xf86RandR12SetRotations(screen, RR_Rotate_0 | RR_Rotate_90 |
833                                 RR_Rotate_180 | RR_Rotate_270 |
834                                 RR_Reflect_X | RR_Reflect_Y);
835         xf86RandR12SetTransformSupport(screen, TRUE);
836     }
837     else {
838         xf86RandR12SetRotations(screen, RR_Rotate_0);
839         xf86RandR12SetTransformSupport(screen, FALSE);
840     }
841 
842     /* Wrap CreateScreenResources so we can initialize the RandR code */
843     config->CreateScreenResources = screen->CreateScreenResources;
844     screen->CreateScreenResources = xf86CrtcCreateScreenResources;
845 
846     config->CloseScreen = screen->CloseScreen;
847     screen->CloseScreen = xf86CrtcCloseScreen;
848 
849     /* This might still be marked wrapped from a previous generation */
850     config->BlockHandler = NULL;
851 
852 #ifdef XFreeXDGA
853     _xf86_di_dga_init_internal(screen);
854 #endif
855 #ifdef RANDR_13_INTERFACE
856     return RANDR_INTERFACE_VERSION;
857 #else
858     return TRUE;
859 #endif
860 }
861 
862 static DisplayModePtr
xf86DefaultMode(xf86OutputPtr output,int width,int height)863 xf86DefaultMode(xf86OutputPtr output, int width, int height)
864 {
865     DisplayModePtr target_mode = NULL;
866     DisplayModePtr mode;
867     int target_diff = 0;
868     int target_preferred = 0;
869     int mm_height;
870 
871     mm_height = output->mm_height;
872     if (!mm_height)
873         mm_height = (768 * 25.4) / DEFAULT_DPI;
874     /*
875      * Pick a mode closest to DEFAULT_DPI
876      */
877     for (mode = output->probed_modes; mode; mode = mode->next) {
878         int dpi;
879         int preferred = (((mode->type & M_T_PREFERRED) != 0) +
880                          ((mode->type & M_T_USERPREF) != 0));
881         int diff;
882 
883         if (xf86ModeWidth(mode, output->initial_rotation) > width ||
884             xf86ModeHeight(mode, output->initial_rotation) > height)
885             continue;
886 
887         /* yes, use VDisplay here, not xf86ModeHeight */
888         dpi = (mode->VDisplay * 254) / (mm_height * 10);
889         diff = dpi - DEFAULT_DPI;
890         diff = diff < 0 ? -diff : diff;
891         if (target_mode == NULL || (preferred > target_preferred) ||
892             (preferred == target_preferred && diff < target_diff)) {
893             target_mode = mode;
894             target_diff = diff;
895             target_preferred = preferred;
896         }
897     }
898     return target_mode;
899 }
900 
901 static DisplayModePtr
xf86ClosestMode(xf86OutputPtr output,DisplayModePtr match,Rotation match_rotation,int width,int height)902 xf86ClosestMode(xf86OutputPtr output,
903                 DisplayModePtr match, Rotation match_rotation,
904                 int width, int height)
905 {
906     DisplayModePtr target_mode = NULL;
907     DisplayModePtr mode;
908     int target_diff = 0;
909 
910     /*
911      * Pick a mode closest to the specified mode
912      */
913     for (mode = output->probed_modes; mode; mode = mode->next) {
914         int dx, dy;
915         int diff;
916 
917         if (xf86ModeWidth(mode, output->initial_rotation) > width ||
918             xf86ModeHeight(mode, output->initial_rotation) > height)
919             continue;
920 
921         /* exact matches are preferred */
922         if (output->initial_rotation == match_rotation &&
923             xf86ModesEqual(mode, match))
924             return mode;
925 
926         dx = xf86ModeWidth(match, match_rotation) - xf86ModeWidth(mode,
927                                                                   output->
928                                                                   initial_rotation);
929         dy = xf86ModeHeight(match, match_rotation) - xf86ModeHeight(mode,
930                                                                     output->
931                                                                     initial_rotation);
932         diff = dx * dx + dy * dy;
933         if (target_mode == NULL || diff < target_diff) {
934             target_mode = mode;
935             target_diff = diff;
936         }
937     }
938     return target_mode;
939 }
940 
941 static DisplayModePtr
xf86OutputHasPreferredMode(xf86OutputPtr output,int width,int height)942 xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height)
943 {
944     DisplayModePtr mode;
945 
946     for (mode = output->probed_modes; mode; mode = mode->next) {
947         if (xf86ModeWidth(mode, output->initial_rotation) > width ||
948             xf86ModeHeight(mode, output->initial_rotation) > height)
949             continue;
950 
951         if (mode->type & M_T_PREFERRED)
952             return mode;
953     }
954     return NULL;
955 }
956 
957 static DisplayModePtr
xf86OutputHasUserPreferredMode(xf86OutputPtr output)958 xf86OutputHasUserPreferredMode(xf86OutputPtr output)
959 {
960     DisplayModePtr mode, first = output->probed_modes;
961 
962     for (mode = first; mode && mode->next != first; mode = mode->next)
963         if (mode->type & M_T_USERPREF)
964             return mode;
965 
966     return NULL;
967 }
968 
969 static int
xf86PickCrtcs(ScrnInfoPtr scrn,xf86CrtcPtr * best_crtcs,DisplayModePtr * modes,int n,int width,int height)970 xf86PickCrtcs(ScrnInfoPtr scrn,
971               xf86CrtcPtr * best_crtcs,
972               DisplayModePtr * modes, int n, int width, int height)
973 {
974     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
975     int c, o;
976     xf86OutputPtr output;
977     xf86CrtcPtr crtc;
978     xf86CrtcPtr *crtcs;
979     int best_score;
980     int score;
981     int my_score;
982 
983     if (n == config->num_output)
984         return 0;
985     output = config->output[n];
986 
987     /*
988      * Compute score with this output disabled
989      */
990     best_crtcs[n] = NULL;
991     best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height);
992     if (modes[n] == NULL)
993         return best_score;
994 
995     crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr));
996     if (!crtcs)
997         return best_score;
998 
999     my_score = 1;
1000     /* Score outputs that are known to be connected higher */
1001     if (output->status == XF86OutputStatusConnected)
1002         my_score++;
1003     /* Score outputs with preferred modes higher */
1004     if (xf86OutputHasPreferredMode(output, width, height))
1005         my_score++;
1006     /*
1007      * Select a crtc for this output and
1008      * then attempt to configure the remaining
1009      * outputs
1010      */
1011     for (c = 0; c < config->num_crtc; c++) {
1012         if ((output->possible_crtcs & (1 << c)) == 0)
1013             continue;
1014 
1015         crtc = config->crtc[c];
1016         /*
1017          * Check to see if some other output is
1018          * using this crtc
1019          */
1020         for (o = 0; o < n; o++)
1021             if (best_crtcs[o] == crtc)
1022                 break;
1023         if (o < n) {
1024             /*
1025              * If the two outputs desire the same mode,
1026              * see if they can be cloned
1027              */
1028             if (xf86ModesEqual(modes[o], modes[n]) &&
1029                 config->output[o]->initial_rotation ==
1030                 config->output[n]->initial_rotation &&
1031                 config->output[o]->initial_x == config->output[n]->initial_x &&
1032                 config->output[o]->initial_y == config->output[n]->initial_y) {
1033                 if ((output->possible_clones & (1 << o)) == 0)
1034                     continue;   /* nope, try next CRTC */
1035             }
1036             else
1037                 continue;       /* different modes, can't clone */
1038         }
1039         crtcs[n] = crtc;
1040         memcpy(crtcs, best_crtcs, n * sizeof(xf86CrtcPtr));
1041         score =
1042             my_score + xf86PickCrtcs(scrn, crtcs, modes, n + 1, width, height);
1043         if (score > best_score) {
1044             best_score = score;
1045             memcpy(best_crtcs, crtcs, config->num_output * sizeof(xf86CrtcPtr));
1046         }
1047     }
1048     free(crtcs);
1049     return best_score;
1050 }
1051 
1052 /*
1053  * Compute the virtual size necessary to place all of the available
1054  * crtcs in the specified configuration.
1055  *
1056  * canGrow indicates that the driver can make the screen larger than its initial
1057  * configuration.  If FALSE, this function will enlarge the screen to include
1058  * the largest available mode.
1059  */
1060 
1061 static void
xf86DefaultScreenLimits(ScrnInfoPtr scrn,int * widthp,int * heightp,Bool canGrow)1062 xf86DefaultScreenLimits(ScrnInfoPtr scrn, int *widthp, int *heightp,
1063                         Bool canGrow)
1064 {
1065     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1066     int width = 0, height = 0;
1067     int o;
1068     int c;
1069     int s;
1070 
1071     for (c = 0; c < config->num_crtc; c++) {
1072         int crtc_width = 0, crtc_height = 0;
1073         xf86CrtcPtr crtc = config->crtc[c];
1074 
1075         if (crtc->enabled) {
1076             crtc_width =
1077                 crtc->desiredX + xf86ModeWidth(&crtc->desiredMode,
1078                                                crtc->desiredRotation);
1079             crtc_height =
1080                 crtc->desiredY + xf86ModeHeight(&crtc->desiredMode,
1081                                                 crtc->desiredRotation);
1082         }
1083         if (!canGrow) {
1084             for (o = 0; o < config->num_output; o++) {
1085                 xf86OutputPtr output = config->output[o];
1086 
1087                 for (s = 0; s < config->num_crtc; s++)
1088                     if (output->possible_crtcs & (1 << s)) {
1089                         DisplayModePtr mode;
1090 
1091                         for (mode = output->probed_modes; mode;
1092                              mode = mode->next) {
1093                             if (mode->HDisplay > crtc_width)
1094                                 crtc_width = mode->HDisplay;
1095                             if (mode->VDisplay > crtc_width)
1096                                 crtc_width = mode->VDisplay;
1097                             if (mode->VDisplay > crtc_height)
1098                                 crtc_height = mode->VDisplay;
1099                             if (mode->HDisplay > crtc_height)
1100                                 crtc_height = mode->HDisplay;
1101                         }
1102                     }
1103             }
1104         }
1105         if (crtc_width > width)
1106             width = crtc_width;
1107         if (crtc_height > height)
1108             height = crtc_height;
1109     }
1110     if (config->maxWidth && width > config->maxWidth)
1111         width = config->maxWidth;
1112     if (config->maxHeight && height > config->maxHeight)
1113         height = config->maxHeight;
1114     if (config->minWidth && width < config->minWidth)
1115         width = config->minWidth;
1116     if (config->minHeight && height < config->minHeight)
1117         height = config->minHeight;
1118     *widthp = width;
1119     *heightp = height;
1120 }
1121 
1122 #define POSITION_UNSET	-100000
1123 
1124 /*
1125  * check if the user configured any outputs at all
1126  * with either a position or a relative setting or a mode.
1127  */
1128 static Bool
xf86UserConfiguredOutputs(ScrnInfoPtr scrn,DisplayModePtr * modes)1129 xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr * modes)
1130 {
1131     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1132     int o;
1133     Bool user_conf = FALSE;
1134 
1135     for (o = 0; o < config->num_output; o++) {
1136         xf86OutputPtr output = config->output[o];
1137         const char *position;
1138         const char *relative_name;
1139         OutputOpts relation;
1140         int r;
1141 
1142         static const OutputOpts relations[] = {
1143             OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
1144         };
1145 
1146         position = xf86GetOptValString(output->options, OPTION_POSITION);
1147         if (position)
1148             user_conf = TRUE;
1149 
1150         relation = 0;
1151         relative_name = NULL;
1152         for (r = 0; r < 4; r++) {
1153             relation = relations[r];
1154             relative_name = xf86GetOptValString(output->options, relation);
1155             if (relative_name)
1156                 break;
1157         }
1158         if (relative_name)
1159             user_conf = TRUE;
1160 
1161         modes[o] = xf86OutputHasUserPreferredMode(output);
1162         if (modes[o])
1163             user_conf = TRUE;
1164     }
1165 
1166     return user_conf;
1167 }
1168 
1169 static Bool
xf86InitialOutputPositions(ScrnInfoPtr scrn,DisplayModePtr * modes)1170 xf86InitialOutputPositions(ScrnInfoPtr scrn, DisplayModePtr * modes)
1171 {
1172     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1173     int o;
1174     int min_x, min_y;
1175 
1176     /* check for initial right-of heuristic */
1177     for (o = 0; o < config->num_output; o++)
1178     {
1179         xf86OutputPtr output = config->output[o];
1180 
1181         if (output->initial_x || output->initial_y)
1182             return TRUE;
1183     }
1184 
1185     for (o = 0; o < config->num_output; o++) {
1186         xf86OutputPtr output = config->output[o];
1187 
1188         output->initial_x = output->initial_y = POSITION_UNSET;
1189     }
1190 
1191     /*
1192      * Loop until all outputs are set
1193      */
1194     for (;;) {
1195         Bool any_set = FALSE;
1196         Bool keep_going = FALSE;
1197 
1198         for (o = 0; o < config->num_output; o++) {
1199             static const OutputOpts relations[] = {
1200                 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
1201             };
1202             xf86OutputPtr output = config->output[o];
1203             xf86OutputPtr relative;
1204             const char *relative_name;
1205             const char *position;
1206             OutputOpts relation;
1207             int r;
1208 
1209             if (output->initial_x != POSITION_UNSET)
1210                 continue;
1211             position = xf86GetOptValString(output->options, OPTION_POSITION);
1212             /*
1213              * Absolute position wins
1214              */
1215             if (position) {
1216                 int x, y;
1217 
1218                 if (sscanf(position, "%d %d", &x, &y) == 2) {
1219                     output->initial_x = x;
1220                     output->initial_y = y;
1221                 }
1222                 else {
1223                     xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1224                                "Output %s position not of form \"x y\"\n",
1225                                output->name);
1226                     output->initial_x = output->initial_y = 0;
1227                 }
1228                 any_set = TRUE;
1229                 continue;
1230             }
1231             /*
1232              * Next comes relative positions
1233              */
1234             relation = 0;
1235             relative_name = NULL;
1236             for (r = 0; r < 4; r++) {
1237                 relation = relations[r];
1238                 relative_name = xf86GetOptValString(output->options, relation);
1239                 if (relative_name)
1240                     break;
1241             }
1242             if (relative_name) {
1243                 int or;
1244 
1245                 relative = NULL;
1246                 for (or = 0; or < config->num_output; or++) {
1247                     xf86OutputPtr out_rel = config->output[or];
1248                     XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor;
1249 
1250                     if (rel_mon) {
1251                         if (xf86nameCompare(rel_mon->mon_identifier,
1252                                             relative_name) == 0) {
1253                             relative = config->output[or];
1254                             break;
1255                         }
1256                     }
1257                     if (strcmp(out_rel->name, relative_name) == 0) {
1258                         relative = config->output[or];
1259                         break;
1260                     }
1261                 }
1262                 if (!relative) {
1263                     xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1264                                "Cannot position output %s relative to unknown output %s\n",
1265                                output->name, relative_name);
1266                     output->initial_x = 0;
1267                     output->initial_y = 0;
1268                     any_set = TRUE;
1269                     continue;
1270                 }
1271                 if (!modes[or]) {
1272                     xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1273                                "Cannot position output %s relative to output %s without modes\n",
1274                                output->name, relative_name);
1275                     output->initial_x = 0;
1276                     output->initial_y = 0;
1277                     any_set = TRUE;
1278                     continue;
1279                 }
1280                 if (relative->initial_x == POSITION_UNSET) {
1281                     keep_going = TRUE;
1282                     continue;
1283                 }
1284                 output->initial_x = relative->initial_x;
1285                 output->initial_y = relative->initial_y;
1286                 switch (relation) {
1287                 case OPTION_BELOW:
1288                     output->initial_y +=
1289                         xf86ModeHeight(modes[or], relative->initial_rotation);
1290                     break;
1291                 case OPTION_RIGHT_OF:
1292                     output->initial_x +=
1293                         xf86ModeWidth(modes[or], relative->initial_rotation);
1294                     break;
1295                 case OPTION_ABOVE:
1296                     if (modes[o])
1297                         output->initial_y -=
1298                             xf86ModeHeight(modes[o], output->initial_rotation);
1299                     break;
1300                 case OPTION_LEFT_OF:
1301                     if (modes[o])
1302                         output->initial_x -=
1303                             xf86ModeWidth(modes[o], output->initial_rotation);
1304                     break;
1305                 default:
1306                     break;
1307                 }
1308                 any_set = TRUE;
1309                 continue;
1310             }
1311 
1312             /* Nothing set, just stick them at 0,0 */
1313             output->initial_x = 0;
1314             output->initial_y = 0;
1315             any_set = TRUE;
1316         }
1317         if (!keep_going)
1318             break;
1319         if (!any_set) {
1320             for (o = 0; o < config->num_output; o++) {
1321                 xf86OutputPtr output = config->output[o];
1322 
1323                 if (output->initial_x == POSITION_UNSET) {
1324                     xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1325                                "Output position loop. Moving %s to 0,0\n",
1326                                output->name);
1327                     output->initial_x = output->initial_y = 0;
1328                     break;
1329                 }
1330             }
1331         }
1332     }
1333 
1334     /*
1335      * normalize positions
1336      */
1337     min_x = 1000000;
1338     min_y = 1000000;
1339     for (o = 0; o < config->num_output; o++) {
1340         xf86OutputPtr output = config->output[o];
1341 
1342         if (output->initial_x < min_x)
1343             min_x = output->initial_x;
1344         if (output->initial_y < min_y)
1345             min_y = output->initial_y;
1346     }
1347 
1348     for (o = 0; o < config->num_output; o++) {
1349         xf86OutputPtr output = config->output[o];
1350 
1351         output->initial_x -= min_x;
1352         output->initial_y -= min_y;
1353     }
1354     return TRUE;
1355 }
1356 
1357 static void
xf86InitialPanning(ScrnInfoPtr scrn)1358 xf86InitialPanning(ScrnInfoPtr scrn)
1359 {
1360     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1361     int o;
1362 
1363     for (o = 0; o < config->num_output; o++) {
1364         xf86OutputPtr output = config->output[o];
1365         const char *panning = xf86GetOptValString(output->options, OPTION_PANNING);
1366         int width, height, left, top;
1367         int track_width, track_height, track_left, track_top;
1368         int brdr[4];
1369 
1370         memset(&output->initialTotalArea, 0, sizeof(BoxRec));
1371         memset(&output->initialTrackingArea, 0, sizeof(BoxRec));
1372         memset(output->initialBorder, 0, 4 * sizeof(INT16));
1373 
1374         if (!panning)
1375             continue;
1376 
1377         switch (sscanf(panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
1378                        &width, &height, &left, &top,
1379                        &track_width, &track_height, &track_left, &track_top,
1380                        &brdr[0], &brdr[1], &brdr[2], &brdr[3])) {
1381         case 12:
1382             output->initialBorder[0] = brdr[0];
1383             output->initialBorder[1] = brdr[1];
1384             output->initialBorder[2] = brdr[2];
1385             output->initialBorder[3] = brdr[3];
1386             /* fall through */
1387         case 8:
1388             output->initialTrackingArea.x1 = track_left;
1389             output->initialTrackingArea.y1 = track_top;
1390             output->initialTrackingArea.x2 = track_left + track_width;
1391             output->initialTrackingArea.y2 = track_top + track_height;
1392             /* fall through */
1393         case 4:
1394             output->initialTotalArea.x1 = left;
1395             output->initialTotalArea.y1 = top;
1396             /* fall through */
1397         case 2:
1398             output->initialTotalArea.x2 = output->initialTotalArea.x1 + width;
1399             output->initialTotalArea.y2 = output->initialTotalArea.y1 + height;
1400             break;
1401         default:
1402             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1403                        "Broken panning specification '%s' for output %s in config file\n",
1404                        panning, output->name);
1405         }
1406     }
1407 }
1408 
1409 /** Return - 0 + if a should be earlier, same or later than b in list
1410  */
1411 static int
xf86ModeCompare(DisplayModePtr a,DisplayModePtr b)1412 xf86ModeCompare(DisplayModePtr a, DisplayModePtr b)
1413 {
1414     int diff;
1415 
1416     diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0);
1417     if (diff)
1418         return diff;
1419     diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay;
1420     if (diff)
1421         return diff;
1422     diff = b->Clock - a->Clock;
1423     return diff;
1424 }
1425 
1426 /**
1427  * Insertion sort input in-place and return the resulting head
1428  */
1429 static DisplayModePtr
xf86SortModes(DisplayModePtr input)1430 xf86SortModes(DisplayModePtr input)
1431 {
1432     DisplayModePtr output = NULL, i, o, n, *op, prev;
1433 
1434     /* sort by preferred status and pixel area */
1435     while (input) {
1436         i = input;
1437         input = input->next;
1438         for (op = &output; (o = *op); op = &o->next)
1439             if (xf86ModeCompare(o, i) > 0)
1440                 break;
1441         i->next = *op;
1442         *op = i;
1443     }
1444     /* prune identical modes */
1445     for (o = output; o && (n = o->next); o = n) {
1446         if (!strcmp(o->name, n->name) && xf86ModesEqual(o, n)) {
1447             o->next = n->next;
1448             free((void *) n->name);
1449             free(n);
1450             n = o;
1451         }
1452     }
1453     /* hook up backward links */
1454     prev = NULL;
1455     for (o = output; o; o = o->next) {
1456         o->prev = prev;
1457         prev = o;
1458     }
1459     return output;
1460 }
1461 
1462 static const char *
preferredMode(ScrnInfoPtr pScrn,xf86OutputPtr output)1463 preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output)
1464 {
1465     const char *preferred_mode = NULL;
1466 
1467     /* Check for a configured preference for a particular mode */
1468     preferred_mode = xf86GetOptValString(output->options,
1469                                          OPTION_PREFERRED_MODE);
1470     if (preferred_mode)
1471         return preferred_mode;
1472 
1473     if (pScrn->display->modes && *pScrn->display->modes)
1474         preferred_mode = *pScrn->display->modes;
1475 
1476     return preferred_mode;
1477 }
1478 
1479 /** identify a token
1480  * args
1481  *   *src     a string with zero or more tokens, e.g. "tok0 tok1",
1482  *   **token  stores a pointer to the first token character,
1483  *   *len     stores the token length.
1484  * return
1485  *   a pointer into src[] at the token terminating character, or
1486  *   NULL if no token is found.
1487  */
1488 static const char *
gettoken(const char * src,const char ** token,int * len)1489 gettoken(const char *src, const char **token, int *len)
1490 {
1491     const char *delim = " \t";
1492     int skip;
1493 
1494     if (!src)
1495         return NULL;
1496 
1497     skip = strspn(src, delim);
1498     *token = &src[skip];
1499 
1500     *len = strcspn(*token, delim);
1501     /* Support for backslash escaped delimiters could be implemented
1502      * here.
1503      */
1504 
1505     /* (*token)[0] != '\0'  <==>  *len > 0 */
1506     if (*len > 0)
1507         return &(*token)[*len];
1508     else
1509         return NULL;
1510 }
1511 
1512 /** Check for a user configured zoom mode list, Option "ZoomModes":
1513  *
1514  * Section "Monitor"
1515  *   Identifier "a21inch"
1516  *   Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480"
1517  * EndSection
1518  *
1519  * Each user mode name is searched for independently so the list
1520  * specification order is free.  An output mode is matched at most
1521  * once, a mode with an already set M_T_USERDEF type bit is skipped.
1522  * Thus a repeat mode name specification matches the next output mode
1523  * with the same name.
1524  *
1525  * Ctrl+Alt+Keypad-{Plus,Minus} zooms {in,out} by selecting the
1526  * {next,previous} M_T_USERDEF mode in the screen modes list, itself
1527  * sorted toward lower dot area or lower dot clock frequency, see
1528  *   modes/xf86Crtc.c: xf86SortModes() xf86SetScrnInfoModes(), and
1529  *   common/xf86Cursor.c: xf86ZoomViewport().
1530  */
1531 static int
processZoomModes(xf86OutputPtr output)1532 processZoomModes(xf86OutputPtr output)
1533 {
1534     const char *zoom_modes;
1535     int count = 0;
1536 
1537     zoom_modes = xf86GetOptValString(output->options, OPTION_ZOOM_MODES);
1538 
1539     if (zoom_modes) {
1540         const char *token, *next;
1541         int len;
1542 
1543         next = gettoken(zoom_modes, &token, &len);
1544         while (next) {
1545             DisplayModePtr mode;
1546 
1547             for (mode = output->probed_modes; mode; mode = mode->next)
1548                 if (!strncmp(token, mode->name, len)  /* prefix match */
1549                     && mode->name[len] == '\0'        /* equal length */
1550                     && !(mode->type & M_T_USERDEF)) { /* no rematch */
1551                     mode->type |= M_T_USERDEF;
1552                     break;
1553                 }
1554 
1555             count++;
1556             next = gettoken(next, &token, &len);
1557         }
1558     }
1559 
1560     return count;
1561 }
1562 
1563 static void
GuessRangeFromModes(MonPtr mon,DisplayModePtr mode)1564 GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
1565 {
1566     if (!mon || !mode)
1567         return;
1568 
1569     mon->nHsync = 1;
1570     mon->hsync[0].lo = 1024.0;
1571     mon->hsync[0].hi = 0.0;
1572 
1573     mon->nVrefresh = 1;
1574     mon->vrefresh[0].lo = 1024.0;
1575     mon->vrefresh[0].hi = 0.0;
1576 
1577     while (mode) {
1578         if (!mode->HSync)
1579             mode->HSync = ((float) mode->Clock) / ((float) mode->HTotal);
1580 
1581         if (!mode->VRefresh)
1582             mode->VRefresh = (1000.0 * ((float) mode->Clock)) /
1583                 ((float) (mode->HTotal * mode->VTotal));
1584 
1585         if (mode->HSync < mon->hsync[0].lo)
1586             mon->hsync[0].lo = mode->HSync;
1587 
1588         if (mode->HSync > mon->hsync[0].hi)
1589             mon->hsync[0].hi = mode->HSync;
1590 
1591         if (mode->VRefresh < mon->vrefresh[0].lo)
1592             mon->vrefresh[0].lo = mode->VRefresh;
1593 
1594         if (mode->VRefresh > mon->vrefresh[0].hi)
1595             mon->vrefresh[0].hi = mode->VRefresh;
1596 
1597         mode = mode->next;
1598     }
1599 
1600     /* stretch out the bottom to fit 640x480@60 */
1601     if (mon->hsync[0].lo > 31.0)
1602         mon->hsync[0].lo = 31.0;
1603     if (mon->vrefresh[0].lo > 58.0)
1604         mon->vrefresh[0].lo = 58.0;
1605 }
1606 
1607 enum det_monrec_source {
1608     sync_config, sync_edid, sync_default
1609 };
1610 
1611 struct det_monrec_parameter {
1612     MonRec *mon_rec;
1613     int *max_clock;
1614     Bool set_hsync;
1615     Bool set_vrefresh;
1616     enum det_monrec_source *sync_source;
1617 };
1618 
1619 static void
handle_detailed_monrec(struct detailed_monitor_section * det_mon,void * data)1620 handle_detailed_monrec(struct detailed_monitor_section *det_mon, void *data)
1621 {
1622     struct det_monrec_parameter *p;
1623 
1624     p = (struct det_monrec_parameter *) data;
1625 
1626     if (det_mon->type == DS_RANGES) {
1627         struct monitor_ranges *ranges = &det_mon->section.ranges;
1628 
1629         if (p->set_hsync && ranges->max_h) {
1630             p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h;
1631             p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h;
1632             p->mon_rec->nHsync++;
1633             if (*p->sync_source == sync_default)
1634                 *p->sync_source = sync_edid;
1635         }
1636         if (p->set_vrefresh && ranges->max_v) {
1637             p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v;
1638             p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v;
1639             p->mon_rec->nVrefresh++;
1640             if (*p->sync_source == sync_default)
1641                 *p->sync_source = sync_edid;
1642         }
1643         if (ranges->max_clock * 1000 > *p->max_clock)
1644             *p->max_clock = ranges->max_clock * 1000;
1645     }
1646 }
1647 
1648 void
xf86ProbeOutputModes(ScrnInfoPtr scrn,int maxX,int maxY)1649 xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY)
1650 {
1651     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1652     int o;
1653 
1654     /* When canGrow was TRUE in the initial configuration we have to
1655      * compare against the maximum values so that we don't drop modes.
1656      * When canGrow was FALSE, the maximum values would have been clamped
1657      * anyway.
1658      */
1659     if (maxX == 0 || maxY == 0) {
1660         maxX = config->maxWidth;
1661         maxY = config->maxHeight;
1662     }
1663 
1664     /* Probe the list of modes for each output. */
1665     for (o = 0; o < config->num_output; o++) {
1666         xf86OutputPtr output = config->output[o];
1667         DisplayModePtr mode;
1668         DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL;
1669         const char *preferred_mode;
1670         xf86MonPtr edid_monitor;
1671         XF86ConfMonitorPtr conf_monitor;
1672         MonRec mon_rec;
1673         int min_clock = 0;
1674         int max_clock = 0;
1675         double clock;
1676         Bool add_default_modes;
1677         Bool debug_modes = config->debug_modes || xf86Initialising;
1678         enum det_monrec_source sync_source = sync_default;
1679 
1680         while (output->probed_modes != NULL)
1681             xf86DeleteMode(&output->probed_modes, output->probed_modes);
1682 
1683         /*
1684          * Check connection status
1685          */
1686         output->status = (*output->funcs->detect) (output);
1687 
1688         if (output->status == XF86OutputStatusDisconnected &&
1689             !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) {
1690             xf86OutputSetEDID(output, NULL);
1691             continue;
1692         }
1693 
1694         memset(&mon_rec, '\0', sizeof(mon_rec));
1695 
1696         conf_monitor = output->conf_monitor;
1697 
1698         if (conf_monitor) {
1699             int i;
1700 
1701             for (i = 0; i < conf_monitor->mon_n_hsync; i++) {
1702                 mon_rec.hsync[mon_rec.nHsync].lo =
1703                     conf_monitor->mon_hsync[i].lo;
1704                 mon_rec.hsync[mon_rec.nHsync].hi =
1705                     conf_monitor->mon_hsync[i].hi;
1706                 mon_rec.nHsync++;
1707                 sync_source = sync_config;
1708             }
1709             for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) {
1710                 mon_rec.vrefresh[mon_rec.nVrefresh].lo =
1711                     conf_monitor->mon_vrefresh[i].lo;
1712                 mon_rec.vrefresh[mon_rec.nVrefresh].hi =
1713                     conf_monitor->mon_vrefresh[i].hi;
1714                 mon_rec.nVrefresh++;
1715                 sync_source = sync_config;
1716             }
1717             config_modes = xf86GetMonitorModes(scrn, conf_monitor);
1718         }
1719 
1720         output_modes = (*output->funcs->get_modes) (output);
1721 
1722         /*
1723          * If the user has a preference, respect it.
1724          * Otherwise, don't second-guess the driver.
1725          */
1726         if (!xf86GetOptValBool(output->options, OPTION_DEFAULT_MODES,
1727                                &add_default_modes))
1728             add_default_modes = (output_modes == NULL);
1729 
1730         edid_monitor = output->MonInfo;
1731 
1732         if (edid_monitor) {
1733             struct det_monrec_parameter p;
1734             struct cea_data_block *hdmi_db;
1735 
1736             /* if display is not continuous-frequency, don't add default modes */
1737             if (!gtf_supported(edid_monitor))
1738                 add_default_modes = FALSE;
1739 
1740             p.mon_rec = &mon_rec;
1741             p.max_clock = &max_clock;
1742             p.set_hsync = mon_rec.nHsync == 0;
1743             p.set_vrefresh = mon_rec.nVrefresh == 0;
1744             p.sync_source = &sync_source;
1745 
1746             xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p);
1747 
1748             /* Look at the CEA HDMI vendor block for the max TMDS freq */
1749             hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor);
1750             if (hdmi_db && hdmi_db->len >= 7) {
1751                 int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000;
1752                 xf86DrvMsg(scrn->scrnIndex, X_PROBED,
1753                            "HDMI max TMDS frequency %dKHz\n", tmds_freq);
1754                 if (tmds_freq > max_clock)
1755                     max_clock = tmds_freq;
1756             }
1757         }
1758 
1759         if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK,
1760                               OPTUNITS_KHZ, &clock))
1761             min_clock = (int) clock;
1762         if (xf86GetOptValFreq(output->options, OPTION_MAX_CLOCK,
1763                               OPTUNITS_KHZ, &clock))
1764             max_clock = (int) clock;
1765 
1766         /* If we still don't have a sync range, guess wildly */
1767         if (!mon_rec.nHsync || !mon_rec.nVrefresh)
1768             GuessRangeFromModes(&mon_rec, output_modes);
1769 
1770         /*
1771          * These limits will end up setting a 1024x768@60Hz mode by default,
1772          * which seems like a fairly good mode to use when nothing else is
1773          * specified
1774          */
1775         if (mon_rec.nHsync == 0) {
1776             mon_rec.hsync[0].lo = 31.0;
1777             mon_rec.hsync[0].hi = 55.0;
1778             mon_rec.nHsync = 1;
1779         }
1780         if (mon_rec.nVrefresh == 0) {
1781             mon_rec.vrefresh[0].lo = 58.0;
1782             mon_rec.vrefresh[0].hi = 62.0;
1783             mon_rec.nVrefresh = 1;
1784         }
1785 
1786         if (add_default_modes)
1787             default_modes = xf86GetDefaultModes();
1788 
1789         /*
1790          * If this is not an RB monitor, remove RB modes from the default
1791          * pool.  RB modes from the config or the monitor itself are fine.
1792          */
1793         if (!mon_rec.reducedblanking)
1794             xf86ValidateModesReducedBlanking(scrn, default_modes);
1795 
1796         if (sync_source == sync_config) {
1797             /*
1798              * Check output and config modes against sync range from config file
1799              */
1800             xf86ValidateModesSync(scrn, output_modes, &mon_rec);
1801             xf86ValidateModesSync(scrn, config_modes, &mon_rec);
1802         }
1803         /*
1804          * Check default modes against sync range
1805          */
1806         xf86ValidateModesSync(scrn, default_modes, &mon_rec);
1807         /*
1808          * Check default modes against monitor max clock
1809          */
1810         if (max_clock) {
1811             xf86ValidateModesClocks(scrn, default_modes,
1812                                     &min_clock, &max_clock, 1);
1813             xf86ValidateModesClocks(scrn, output_modes,
1814                                     &min_clock, &max_clock, 1);
1815         }
1816 
1817         output->probed_modes = NULL;
1818         output->probed_modes = xf86ModesAdd(output->probed_modes, config_modes);
1819         output->probed_modes = xf86ModesAdd(output->probed_modes, output_modes);
1820         output->probed_modes =
1821             xf86ModesAdd(output->probed_modes, default_modes);
1822 
1823         /*
1824          * Check all modes against max size, interlace, and doublescan
1825          */
1826         if (maxX && maxY)
1827             xf86ValidateModesSize(scrn, output->probed_modes, maxX, maxY, 0);
1828 
1829         {
1830             int flags = (output->interlaceAllowed ? V_INTERLACE : 0) |
1831                 (output->doubleScanAllowed ? V_DBLSCAN : 0);
1832             xf86ValidateModesFlags(scrn, output->probed_modes, flags);
1833         }
1834 
1835         /*
1836          * Check all modes against output
1837          */
1838         for (mode = output->probed_modes; mode != NULL; mode = mode->next)
1839             if (mode->status == MODE_OK)
1840                 mode->status = (*output->funcs->mode_valid) (output, mode);
1841 
1842         xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes);
1843 
1844         output->probed_modes = xf86SortModes(output->probed_modes);
1845 
1846         /* Check for a configured preference for a particular mode */
1847         preferred_mode = preferredMode(scrn, output);
1848 
1849         if (preferred_mode) {
1850             for (mode = output->probed_modes; mode; mode = mode->next) {
1851                 if (!strcmp(preferred_mode, mode->name)) {
1852                     if (mode != output->probed_modes) {
1853                         if (mode->prev)
1854                             mode->prev->next = mode->next;
1855                         if (mode->next)
1856                             mode->next->prev = mode->prev;
1857                         mode->next = output->probed_modes;
1858                         output->probed_modes->prev = mode;
1859                         mode->prev = NULL;
1860                         output->probed_modes = mode;
1861                     }
1862                     mode->type |= (M_T_PREFERRED | M_T_USERPREF);
1863                     break;
1864                 }
1865             }
1866         }
1867 
1868         /* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode: M_T_USERDEF mode type */
1869         processZoomModes(output);
1870 
1871         output->initial_rotation = xf86OutputInitialRotation(output);
1872 
1873         if (debug_modes) {
1874             if (output->probed_modes != NULL) {
1875                 xf86DrvMsg(scrn->scrnIndex, X_INFO,
1876                            "Printing probed modes for output %s\n",
1877                            output->name);
1878             }
1879             else {
1880                 xf86DrvMsg(scrn->scrnIndex, X_INFO,
1881                            "No remaining probed modes for output %s\n",
1882                            output->name);
1883             }
1884         }
1885         for (mode = output->probed_modes; mode != NULL; mode = mode->next) {
1886             /* The code to choose the best mode per pipe later on will require
1887              * VRefresh to be set.
1888              */
1889             mode->VRefresh = xf86ModeVRefresh(mode);
1890             xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
1891 
1892             if (debug_modes)
1893                 xf86PrintModeline(scrn->scrnIndex, mode);
1894         }
1895     }
1896 }
1897 
1898 /**
1899  * Copy one of the output mode lists to the ScrnInfo record
1900  */
1901 
1902 static DisplayModePtr
biggestMode(DisplayModePtr a,DisplayModePtr b)1903 biggestMode(DisplayModePtr a, DisplayModePtr b)
1904 {
1905     int A, B;
1906 
1907     if (!a)
1908         return b;
1909     if (!b)
1910         return a;
1911 
1912     A = a->HDisplay * a->VDisplay;
1913     B = b->HDisplay * b->VDisplay;
1914 
1915     if (A > B)
1916         return a;
1917 
1918     return b;
1919 }
1920 
1921 static xf86OutputPtr
SetCompatOutput(xf86CrtcConfigPtr config)1922 SetCompatOutput(xf86CrtcConfigPtr config)
1923 {
1924     xf86OutputPtr output = NULL, test = NULL;
1925     DisplayModePtr maxmode = NULL, testmode, mode;
1926     int o, compat = -1, count, mincount = 0;
1927 
1928     if (config->num_output == 0)
1929         return NULL;
1930 
1931     /* Look for one that's definitely connected */
1932     for (o = 0; o < config->num_output; o++) {
1933         test = config->output[o];
1934         if (!test->crtc)
1935             continue;
1936         if (test->status != XF86OutputStatusConnected)
1937             continue;
1938         if (!test->probed_modes)
1939             continue;
1940 
1941         testmode = mode = test->probed_modes;
1942         for (count = 0; mode; mode = mode->next, count++)
1943             testmode = biggestMode(testmode, mode);
1944 
1945         if (!output) {
1946             output = test;
1947             compat = o;
1948             maxmode = testmode;
1949             mincount = count;
1950         }
1951         else if (maxmode == biggestMode(maxmode, testmode)) {
1952             output = test;
1953             compat = o;
1954             maxmode = testmode;
1955             mincount = count;
1956         }
1957         else if ((maxmode->HDisplay == testmode->HDisplay) &&
1958                  (maxmode->VDisplay == testmode->VDisplay) &&
1959                  count <= mincount) {
1960             output = test;
1961             compat = o;
1962             maxmode = testmode;
1963             mincount = count;
1964         }
1965     }
1966 
1967     /* If we didn't find one, take anything we can get */
1968     if (!output) {
1969         for (o = 0; o < config->num_output; o++) {
1970             test = config->output[o];
1971             if (!test->crtc)
1972                 continue;
1973             if (!test->probed_modes)
1974                 continue;
1975 
1976             if (!output) {
1977                 output = test;
1978                 compat = o;
1979             }
1980             else if (test->probed_modes->HDisplay <
1981                      output->probed_modes->HDisplay) {
1982                 output = test;
1983                 compat = o;
1984             }
1985         }
1986     }
1987 
1988     if (compat >= 0) {
1989         config->compat_output = compat;
1990     }
1991     else if (config->compat_output >= 0 && config->compat_output < config->num_output) {
1992         /* Don't change the compat output when no valid outputs found */
1993         output = config->output[config->compat_output];
1994     }
1995 
1996     /* All outputs are disconnected, select one to fake */
1997     if (!output && config->num_output) {
1998         config->compat_output = 0;
1999         output = config->output[config->compat_output];
2000     }
2001 
2002     return output;
2003 }
2004 
2005 void
xf86SetScrnInfoModes(ScrnInfoPtr scrn)2006 xf86SetScrnInfoModes(ScrnInfoPtr scrn)
2007 {
2008     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2009     xf86OutputPtr output;
2010     xf86CrtcPtr crtc;
2011     DisplayModePtr last, mode = NULL;
2012 
2013     output = SetCompatOutput(config);
2014 
2015     if (!output)
2016         return;                 /* punt */
2017 
2018     crtc = output->crtc;
2019 
2020     /* Clear any existing modes from scrn->modes */
2021     while (scrn->modes != NULL)
2022         xf86DeleteMode(&scrn->modes, scrn->modes);
2023 
2024     /* Set scrn->modes to the mode list for the 'compat' output */
2025     scrn->modes = xf86DuplicateModes(scrn, output->probed_modes);
2026 
2027     if (crtc) {
2028         for (mode = scrn->modes; mode; mode = mode->next)
2029             if (xf86ModesEqual(mode, &crtc->desiredMode))
2030                 break;
2031     }
2032 
2033     if (!scrn->modes) {
2034         scrn->modes = xf86ModesAdd(scrn->modes,
2035                                    xf86CVTMode(scrn->display->virtualX,
2036                                                scrn->display->virtualY,
2037                                                60, 0, 0));
2038     }
2039 
2040     /* For some reason, scrn->modes is circular, unlike the other mode
2041      * lists.  How great is that?
2042      */
2043     for (last = scrn->modes; last && last->next; last = last->next);
2044     last->next = scrn->modes;
2045     scrn->modes->prev = last;
2046     if (mode) {
2047         while (scrn->modes != mode)
2048             scrn->modes = scrn->modes->next;
2049     }
2050 
2051     scrn->currentMode = scrn->modes;
2052 #ifdef XFreeXDGA
2053     if (scrn->pScreen)
2054         _xf86_di_dga_reinit_internal(scrn->pScreen);
2055 #endif
2056 }
2057 
2058 static Bool
xf86CollectEnabledOutputs(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,Bool * enabled)2059 xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2060                           Bool *enabled)
2061 {
2062     Bool any_enabled = FALSE;
2063     int o;
2064 
2065     /*
2066      * Don't bother enabling outputs on GPU screens: a client needs to attach
2067      * it to a source provider before setting a mode that scans out a shared
2068      * pixmap.
2069      */
2070     if (scrn->is_gpu)
2071         return FALSE;
2072 
2073     for (o = 0; o < config->num_output; o++)
2074         any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE);
2075 
2076     if (!any_enabled) {
2077         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2078                    "No outputs definitely connected, trying again...\n");
2079 
2080         for (o = 0; o < config->num_output; o++)
2081             any_enabled |= enabled[o] =
2082                 xf86OutputEnabled(config->output[o], FALSE);
2083     }
2084 
2085     return any_enabled;
2086 }
2087 
2088 static Bool
nextEnabledOutput(xf86CrtcConfigPtr config,Bool * enabled,int * index)2089 nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index)
2090 {
2091     int o = *index;
2092 
2093     for (o++; o < config->num_output; o++) {
2094         if (enabled[o]) {
2095             *index = o;
2096             return TRUE;
2097         }
2098     }
2099 
2100     return FALSE;
2101 }
2102 
2103 static Bool
aspectMatch(float a,float b)2104 aspectMatch(float a, float b)
2105 {
2106     return fabs(1 - (a / b)) < 0.05;
2107 }
2108 
2109 static DisplayModePtr
nextAspectMode(xf86OutputPtr o,DisplayModePtr last,float aspect)2110 nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect)
2111 {
2112     DisplayModePtr m = NULL;
2113 
2114     if (!o)
2115         return NULL;
2116 
2117     if (!last)
2118         m = o->probed_modes;
2119     else
2120         m = last->next;
2121 
2122     for (; m; m = m->next)
2123         if (aspectMatch(aspect, (float) m->HDisplay / (float) m->VDisplay))
2124             return m;
2125 
2126     return NULL;
2127 }
2128 
2129 static DisplayModePtr
bestModeForAspect(xf86CrtcConfigPtr config,Bool * enabled,float aspect)2130 bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
2131 {
2132     int o = -1, p;
2133     DisplayModePtr mode = NULL, test = NULL, match = NULL;
2134 
2135     if (!nextEnabledOutput(config, enabled, &o))
2136         return NULL;
2137     while ((mode = nextAspectMode(config->output[o], mode, aspect))) {
2138         test = mode;
2139         for (p = o; nextEnabledOutput(config, enabled, &p);) {
2140             test = xf86OutputFindClosestMode(config->output[p], mode);
2141             if (!test)
2142                 break;
2143             if (test->HDisplay != mode->HDisplay ||
2144                 test->VDisplay != mode->VDisplay) {
2145                 test = NULL;
2146                 break;
2147             }
2148         }
2149 
2150         /* if we didn't match it on all outputs, try the next one */
2151         if (!test)
2152             continue;
2153 
2154         /* if it's bigger than the last one, save it */
2155         if (!match || (test->HDisplay > match->HDisplay))
2156             match = test;
2157     }
2158 
2159     /* return the biggest one found */
2160     return match;
2161 }
2162 
2163 static int
numEnabledOutputs(xf86CrtcConfigPtr config,Bool * enabled)2164 numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled)
2165 {
2166     int i = 0, p;
2167 
2168     for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
2169 
2170     return i;
2171 }
2172 
2173 static Bool
xf86TargetRightOf(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,DisplayModePtr * modes,Bool * enabled,int width,int height)2174 xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2175                   DisplayModePtr *modes, Bool *enabled,
2176                   int width, int height)
2177 {
2178     int o;
2179     int w = 0;
2180     Bool has_tile = FALSE;
2181     uint32_t configured_outputs;
2182 
2183     xf86GetOptValBool(config->options, OPTION_PREFER_CLONEMODE,
2184                       &scrn->preferClone);
2185     if (scrn->preferClone)
2186         return FALSE;
2187 
2188     if (numEnabledOutputs(config, enabled) < 2)
2189         return FALSE;
2190 
2191     for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2192         DisplayModePtr mode =
2193             xf86OutputHasPreferredMode(config->output[o], width, height);
2194 
2195         if (!mode)
2196             return FALSE;
2197 
2198         w += mode->HDisplay;
2199     }
2200 
2201     if (w > width)
2202         return FALSE;
2203 
2204     w = 0;
2205     configured_outputs = 0;
2206 
2207     for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2208         DisplayModePtr mode =
2209             xf86OutputHasPreferredMode(config->output[o], width, height);
2210 
2211         if (configured_outputs & (1 << o))
2212             continue;
2213 
2214         if (config->output[o]->tile_info.group_id) {
2215             has_tile = TRUE;
2216             continue;
2217         }
2218 
2219         config->output[o]->initial_x = w;
2220         w += mode->HDisplay;
2221 
2222         configured_outputs |= (1 << o);
2223         modes[o] = mode;
2224     }
2225 
2226     if (has_tile) {
2227         for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2228             int ht, vt, ot;
2229             int add_x, cur_x = w;
2230             struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile;
2231             if (configured_outputs & (1 << o))
2232                 continue;
2233             if (!tile_info->group_id)
2234                 continue;
2235 
2236             if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0)
2237                 continue;
2238 
2239             for (ht = 0; ht < tile_info->num_h_tile; ht++) {
2240                 int cur_y = 0;
2241                 add_x = 0;
2242                 for (vt = 0; vt < tile_info->num_v_tile; vt++) {
2243 
2244                     for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) {
2245 
2246                         DisplayModePtr mode =
2247                             xf86OutputHasPreferredMode(config->output[ot], width, height);
2248                         if (!config->output[ot]->tile_info.group_id)
2249                             continue;
2250 
2251                         this_tile = &config->output[ot]->tile_info;
2252                         if (this_tile->group_id != tile_info->group_id)
2253                             continue;
2254 
2255                         if (this_tile->tile_h_loc != ht ||
2256                             this_tile->tile_v_loc != vt)
2257                             continue;
2258 
2259                         config->output[ot]->initial_x = cur_x;
2260                         config->output[ot]->initial_y = cur_y;
2261 
2262                         if (vt == 0)
2263                             add_x = this_tile->tile_h_size;
2264                         cur_y += this_tile->tile_v_size;
2265                         configured_outputs |= (1 << ot);
2266                         modes[ot] = mode;
2267                     }
2268                 }
2269                 cur_x += add_x;
2270             }
2271             w = cur_x;
2272         }
2273     }
2274     return TRUE;
2275 }
2276 
2277 static Bool
xf86TargetPreferred(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,DisplayModePtr * modes,Bool * enabled,int width,int height)2278 xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2279                     DisplayModePtr * modes, Bool *enabled,
2280                     int width, int height)
2281 {
2282     int o, p;
2283     int max_pref_width = 0, max_pref_height = 0;
2284     DisplayModePtr *preferred, *preferred_match;
2285     Bool ret = FALSE;
2286 
2287     preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2288     preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2289 
2290     /* Check if the preferred mode is available on all outputs */
2291     for (p = -1; nextEnabledOutput(config, enabled, &p);) {
2292         Rotation r = config->output[p]->initial_rotation;
2293         DisplayModePtr mode;
2294 
2295         if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p],
2296                                                        width, height))) {
2297             int pref_width = xf86ModeWidth(preferred[p], r);
2298             int pref_height = xf86ModeHeight(preferred[p], r);
2299             Bool all_match = TRUE;
2300 
2301             for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2302                 Bool match = FALSE;
2303                 xf86OutputPtr output = config->output[o];
2304 
2305                 if (o == p)
2306                     continue;
2307 
2308                 /*
2309                  * First see if the preferred mode matches on the next
2310                  * output as well.  This catches the common case of identical
2311                  * monitors and makes sure they all have the same timings
2312                  * and refresh.  If that fails, we fall back to trying to
2313                  * match just width & height.
2314                  */
2315                 mode = xf86OutputHasPreferredMode(output, pref_width,
2316                                                   pref_height);
2317                 if (mode && xf86ModesEqual(mode, preferred[p])) {
2318                     preferred[o] = mode;
2319                     match = TRUE;
2320                 }
2321                 else {
2322                     for (mode = output->probed_modes; mode; mode = mode->next) {
2323                         Rotation ir = output->initial_rotation;
2324 
2325                         if (xf86ModeWidth(mode, ir) == pref_width &&
2326                             xf86ModeHeight(mode, ir) == pref_height) {
2327                             preferred[o] = mode;
2328                             match = TRUE;
2329                         }
2330                     }
2331                 }
2332 
2333                 all_match &= match;
2334             }
2335 
2336             if (all_match &&
2337                 (pref_width * pref_height > max_pref_width * max_pref_height)) {
2338                 for (o = -1; nextEnabledOutput(config, enabled, &o);)
2339                     preferred_match[o] = preferred[o];
2340                 max_pref_width = pref_width;
2341                 max_pref_height = pref_height;
2342                 ret = TRUE;
2343             }
2344         }
2345     }
2346 
2347     /*
2348      * If there's no preferred mode, but only one monitor, pick the
2349      * biggest mode for its aspect ratio or 4:3, assuming one exists.
2350      */
2351     if (!ret)
2352         do {
2353             float aspect = 0.0;
2354             DisplayModePtr a = NULL, b = NULL;
2355 
2356             if (numEnabledOutputs(config, enabled) != 1)
2357                 break;
2358 
2359             p = -1;
2360             nextEnabledOutput(config, enabled, &p);
2361             if (config->output[p]->mm_height)
2362                 aspect = (float) config->output[p]->mm_width /
2363                     (float) config->output[p]->mm_height;
2364 
2365             a = bestModeForAspect(config, enabled, 4.0/3.0);
2366             if (aspect)
2367                 b = bestModeForAspect(config, enabled, aspect);
2368 
2369             preferred_match[p] = biggestMode(a, b);
2370 
2371             if (preferred_match[p])
2372                 ret = TRUE;
2373 
2374         } while (0);
2375 
2376     if (ret) {
2377         /* oh good, there is a match.  stash the selected modes and return. */
2378         memcpy(modes, preferred_match,
2379                config->num_output * sizeof(DisplayModePtr));
2380     }
2381 
2382     free(preferred);
2383     free(preferred_match);
2384     return ret;
2385 }
2386 
2387 static Bool
xf86TargetAspect(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,DisplayModePtr * modes,Bool * enabled,int width,int height)2388 xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2389                  DisplayModePtr * modes, Bool *enabled, int width, int height)
2390 {
2391     int o;
2392     float aspect = 0.0, *aspects;
2393     xf86OutputPtr output;
2394     Bool ret = FALSE;
2395     DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL;
2396 
2397     aspects = xnfcalloc(config->num_output, sizeof(float));
2398 
2399     /* collect the aspect ratios */
2400     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2401         output = config->output[o];
2402         if (output->mm_height)
2403             aspects[o] = (float) output->mm_width / (float) output->mm_height;
2404         else
2405             aspects[o] = 4.0 / 3.0;
2406     }
2407 
2408     /* check that they're all the same */
2409     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2410         output = config->output[o];
2411         if (!aspect) {
2412             aspect = aspects[o];
2413         }
2414         else if (!aspectMatch(aspect, aspects[o])) {
2415             goto no_aspect_match;
2416         }
2417     }
2418 
2419     /* if they're all 4:3, just skip ahead and save effort */
2420     if (!aspectMatch(aspect, 4.0 / 3.0))
2421         aspect_guess = bestModeForAspect(config, enabled, aspect);
2422 
2423  no_aspect_match:
2424     base_guess = bestModeForAspect(config, enabled, 4.0 / 3.0);
2425 
2426     guess = biggestMode(base_guess, aspect_guess);
2427 
2428     if (!guess)
2429         goto out;
2430 
2431     /* found a mode that works everywhere, now apply it */
2432     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2433         modes[o] = xf86OutputFindClosestMode(config->output[o], guess);
2434     }
2435     ret = TRUE;
2436 
2437  out:
2438     free(aspects);
2439     return ret;
2440 }
2441 
2442 static Bool
xf86TargetFallback(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,DisplayModePtr * modes,Bool * enabled,int width,int height)2443 xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2444                    DisplayModePtr * modes, Bool *enabled, int width, int height)
2445 {
2446     DisplayModePtr target_mode = NULL;
2447     Rotation target_rotation = RR_Rotate_0;
2448     DisplayModePtr default_mode;
2449     int default_preferred, target_preferred = 0, o;
2450 
2451     /* User preferred > preferred > other modes */
2452     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2453         default_mode = xf86DefaultMode(config->output[o], width, height);
2454         if (!default_mode)
2455             continue;
2456 
2457         default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) +
2458                              ((default_mode->type & M_T_USERPREF) != 0));
2459 
2460         if (default_preferred > target_preferred || !target_mode) {
2461             target_mode = default_mode;
2462             target_preferred = default_preferred;
2463             target_rotation = config->output[o]->initial_rotation;
2464             config->compat_output = o;
2465         }
2466     }
2467 
2468     if (target_mode)
2469         modes[config->compat_output] = target_mode;
2470 
2471     /* Fill in other output modes */
2472     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2473         if (!modes[o])
2474             modes[o] = xf86ClosestMode(config->output[o], target_mode,
2475                                        target_rotation, width, height);
2476     }
2477 
2478     return target_mode != NULL;
2479 }
2480 
2481 static Bool
xf86TargetUserpref(ScrnInfoPtr scrn,xf86CrtcConfigPtr config,DisplayModePtr * modes,Bool * enabled,int width,int height)2482 xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2483                    DisplayModePtr * modes, Bool *enabled, int width, int height)
2484 {
2485     int o;
2486 
2487     if (xf86UserConfiguredOutputs(scrn, modes))
2488         return xf86TargetFallback(scrn, config, modes, enabled, width, height);
2489 
2490     for (o = -1; nextEnabledOutput(config, enabled, &o);)
2491         if (xf86OutputHasUserPreferredMode(config->output[o]))
2492             return
2493                 xf86TargetFallback(scrn, config, modes, enabled, width, height);
2494 
2495     return FALSE;
2496 }
2497 
2498 void
xf86AssignNoOutputInitialSize(ScrnInfoPtr scrn,const OptionInfoRec * options,int * no_output_width,int * no_output_height)2499 xf86AssignNoOutputInitialSize(ScrnInfoPtr scrn, const OptionInfoRec *options,
2500                               int *no_output_width, int *no_output_height)
2501 {
2502     int width = 0, height = 0;
2503     const char *no_output_size =
2504         xf86GetOptValString(options, OPTION_NO_OUTPUT_INITIAL_SIZE);
2505 
2506     *no_output_width = NO_OUTPUT_DEFAULT_WIDTH;
2507     *no_output_height = NO_OUTPUT_DEFAULT_HEIGHT;
2508 
2509     if (no_output_size == NULL) {
2510         return;
2511     }
2512 
2513     if (sscanf(no_output_size, "%d %d", &width, &height) != 2) {
2514         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2515                    "\"NoOutputInitialSize\" string \"%s\" not of form "
2516                    "\"width height\"\n", no_output_size);
2517         return;
2518     }
2519 
2520     *no_output_width = width;
2521     *no_output_height = height;
2522 }
2523 
2524 /**
2525  * Construct default screen configuration
2526  *
2527  * Given auto-detected (and, eventually, configured) values,
2528  * construct a usable configuration for the system
2529  *
2530  * canGrow indicates that the driver can resize the screen to larger than its
2531  * initially configured size via the config->funcs->resize hook.  If TRUE, this
2532  * function will set virtualX and virtualY to match the initial configuration
2533  * and leave config->max{Width,Height} alone.  If FALSE, it will bloat
2534  * virtual[XY] to include the largest modes and set config->max{Width,Height}
2535  * accordingly.
2536  */
2537 
2538 Bool
xf86InitialConfiguration(ScrnInfoPtr scrn,Bool canGrow)2539 xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow)
2540 {
2541     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2542     int o, c;
2543     xf86CrtcPtr *crtcs;
2544     DisplayModePtr *modes;
2545     Bool *enabled;
2546     int width, height;
2547     int no_output_width, no_output_height;
2548     int i = scrn->scrnIndex;
2549     Bool have_outputs = TRUE;
2550     Bool ret;
2551     Bool success = FALSE;
2552 
2553     /* Set up the device options */
2554     config->options = xnfalloc(sizeof(xf86DeviceOptions));
2555     memcpy(config->options, xf86DeviceOptions, sizeof(xf86DeviceOptions));
2556     xf86ProcessOptions(scrn->scrnIndex, scrn->options, config->options);
2557     config->debug_modes = xf86ReturnOptValBool(config->options,
2558                                                OPTION_MODEDEBUG, FALSE);
2559 
2560     if (scrn->display->virtualX && !scrn->is_gpu)
2561         width = scrn->display->virtualX;
2562     else
2563         width = config->maxWidth;
2564     if (scrn->display->virtualY && !scrn->is_gpu)
2565         height = scrn->display->virtualY;
2566     else
2567         height = config->maxHeight;
2568 
2569     xf86AssignNoOutputInitialSize(scrn, config->options,
2570                                   &no_output_width, &no_output_height);
2571 
2572     xf86ProbeOutputModes(scrn, width, height);
2573 
2574     crtcs = xnfcalloc(config->num_output, sizeof(xf86CrtcPtr));
2575     modes = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2576     enabled = xnfcalloc(config->num_output, sizeof(Bool));
2577 
2578     ret = xf86CollectEnabledOutputs(scrn, config, enabled);
2579     if (ret == FALSE && canGrow) {
2580         if (!scrn->is_gpu)
2581             xf86DrvMsg(i, X_WARNING,
2582 		       "Unable to find connected outputs - setting %dx%d "
2583                        "initial framebuffer\n",
2584                        no_output_width, no_output_height);
2585         have_outputs = FALSE;
2586     }
2587     else {
2588         if (xf86TargetUserpref(scrn, config, modes, enabled, width, height))
2589             xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n");
2590         else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height))
2591             xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n");
2592         else if (xf86TargetPreferred
2593                  (scrn, config, modes, enabled, width, height))
2594             xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n");
2595         else if (xf86TargetAspect(scrn, config, modes, enabled, width, height))
2596             xf86DrvMsg(i, X_INFO,
2597                        "Using fuzzy aspect match for initial modes\n");
2598         else if (xf86TargetFallback
2599                  (scrn, config, modes, enabled, width, height))
2600             xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n");
2601         else
2602             xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n");
2603     }
2604 
2605     for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2606         if (!modes[o])
2607             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2608                        "Output %s enabled but has no modes\n",
2609                        config->output[o]->name);
2610         else
2611             xf86DrvMsg (scrn->scrnIndex, X_INFO,
2612                         "Output %s using initial mode %s +%d+%d\n",
2613                         config->output[o]->name, modes[o]->name,
2614                         config->output[o]->initial_x,
2615                         config->output[o]->initial_y);
2616     }
2617 
2618     /*
2619      * Set the position of each output
2620      */
2621     if (!xf86InitialOutputPositions(scrn, modes))
2622         goto bailout;
2623 
2624     /*
2625      * Set initial panning of each output
2626      */
2627     xf86InitialPanning(scrn);
2628 
2629     /*
2630      * Assign CRTCs to fit output configuration
2631      */
2632     if (have_outputs && !xf86PickCrtcs(scrn, crtcs, modes, 0, width, height))
2633         goto bailout;
2634 
2635     /* XXX override xf86 common frame computation code */
2636 
2637     if (!scrn->is_gpu) {
2638         scrn->display->frameX0 = 0;
2639         scrn->display->frameY0 = 0;
2640     }
2641 
2642     for (c = 0; c < config->num_crtc; c++) {
2643         xf86CrtcPtr crtc = config->crtc[c];
2644 
2645         crtc->enabled = FALSE;
2646         memset(&crtc->desiredMode, '\0', sizeof(crtc->desiredMode));
2647     }
2648 
2649     /*
2650      * Set initial configuration
2651      */
2652     for (o = 0; o < config->num_output; o++) {
2653         xf86OutputPtr output = config->output[o];
2654         DisplayModePtr mode = modes[o];
2655         xf86CrtcPtr crtc = crtcs[o];
2656 
2657         if (mode && crtc) {
2658             xf86SaveModeContents(&crtc->desiredMode, mode);
2659             crtc->desiredRotation = output->initial_rotation;
2660             crtc->desiredX = output->initial_x;
2661             crtc->desiredY = output->initial_y;
2662             crtc->desiredTransformPresent = FALSE;
2663             crtc->enabled = TRUE;
2664             memcpy(&crtc->panningTotalArea, &output->initialTotalArea,
2665                    sizeof(BoxRec));
2666             memcpy(&crtc->panningTrackingArea, &output->initialTrackingArea,
2667                    sizeof(BoxRec));
2668             memcpy(crtc->panningBorder, output->initialBorder,
2669                    4 * sizeof(INT16));
2670             output->crtc = crtc;
2671         }
2672         else {
2673             output->crtc = NULL;
2674         }
2675     }
2676 
2677     if (scrn->display->virtualX == 0 || scrn->is_gpu) {
2678         /*
2679          * Expand virtual size to cover the current config and potential mode
2680          * switches, if the driver can't enlarge the screen later.
2681          */
2682         xf86DefaultScreenLimits(scrn, &width, &height, canGrow);
2683 
2684         if (have_outputs == FALSE) {
2685             if (width < no_output_width &&
2686                 height < no_output_height) {
2687                 width = no_output_width;
2688                 height = no_output_height;
2689             }
2690         }
2691 
2692 	if (!scrn->is_gpu) {
2693             scrn->display->virtualX = width;
2694             scrn->display->virtualY = height;
2695 	}
2696     }
2697 
2698     if (width > scrn->virtualX)
2699         scrn->virtualX = width;
2700     if (height > scrn->virtualY)
2701         scrn->virtualY = height;
2702 
2703     /*
2704      * Make sure the configuration isn't too small.
2705      */
2706     if (width < config->minWidth || height < config->minHeight)
2707         goto bailout;
2708 
2709     /*
2710      * Limit the crtc config to virtual[XY] if the driver can't grow the
2711      * desktop.
2712      */
2713     if (!canGrow) {
2714         xf86CrtcSetSizeRange(scrn, config->minWidth, config->minHeight,
2715                              width, height);
2716     }
2717 
2718     xf86SetScrnInfoModes(scrn);
2719 
2720     success = TRUE;
2721  bailout:
2722     free(crtcs);
2723     free(modes);
2724     free(enabled);
2725     return success;
2726 }
2727 
2728 /* Turn a CRTC off, using the DPMS function and disabling the cursor */
2729 static void
xf86DisableCrtc(xf86CrtcPtr crtc)2730 xf86DisableCrtc(xf86CrtcPtr crtc)
2731 {
2732     if (xf86CrtcIsLeased(crtc))
2733         return;
2734 
2735     crtc->funcs->dpms(crtc, DPMSModeOff);
2736     xf86_crtc_hide_cursor(crtc);
2737 }
2738 
2739 /*
2740  * Check the CRTC we're going to map each output to vs. its current
2741  * CRTC.  If they don't match, we have to disable the output and the CRTC
2742  * since the driver will have to re-route things.
2743  */
2744 static void
xf86PrepareOutputs(ScrnInfoPtr scrn)2745 xf86PrepareOutputs(ScrnInfoPtr scrn)
2746 {
2747     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2748     int o;
2749 
2750     for (o = 0; o < config->num_output; o++) {
2751         xf86OutputPtr output = config->output[o];
2752 
2753         if (xf86OutputIsLeased(output))
2754             continue;
2755 
2756 #if RANDR_GET_CRTC_INTERFACE
2757         /* Disable outputs that are unused or will be re-routed */
2758         if (!output->funcs->get_crtc ||
2759             output->crtc != (*output->funcs->get_crtc) (output) ||
2760             output->crtc == NULL)
2761 #endif
2762             (*output->funcs->dpms) (output, DPMSModeOff);
2763     }
2764 }
2765 
2766 static void
xf86PrepareCrtcs(ScrnInfoPtr scrn)2767 xf86PrepareCrtcs(ScrnInfoPtr scrn)
2768 {
2769     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2770     int c;
2771 
2772     for (c = 0; c < config->num_crtc; c++) {
2773         xf86CrtcPtr crtc = config->crtc[c];
2774 #if RANDR_GET_CRTC_INTERFACE
2775         xf86OutputPtr output = NULL;
2776         uint32_t desired_outputs = 0, current_outputs = 0;
2777         int o;
2778 
2779         if (xf86CrtcIsLeased(crtc))
2780             continue;
2781 
2782         for (o = 0; o < config->num_output; o++) {
2783             output = config->output[o];
2784             if (output->crtc == crtc)
2785                 desired_outputs |= (1 << o);
2786             /* If we can't tell where it's mapped, force it off */
2787             if (!output->funcs->get_crtc) {
2788                 desired_outputs = 0;
2789                 break;
2790             }
2791             if ((*output->funcs->get_crtc) (output) == crtc)
2792                 current_outputs |= (1 << o);
2793         }
2794 
2795         /*
2796          * If mappings are different or the CRTC is unused,
2797          * we need to disable it
2798          */
2799         if (desired_outputs != current_outputs || !desired_outputs)
2800             xf86DisableCrtc(crtc);
2801 #else
2802         if (xf86CrtcIsLeased(crtc))
2803             continue;
2804 
2805         xf86DisableCrtc(crtc);
2806 #endif
2807     }
2808 }
2809 
2810 /*
2811  * Using the desired mode information in each crtc, set
2812  * modes (used in EnterVT functions, or at server startup)
2813  */
2814 
2815 Bool
xf86SetDesiredModes(ScrnInfoPtr scrn)2816 xf86SetDesiredModes(ScrnInfoPtr scrn)
2817 {
2818     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2819     xf86CrtcPtr crtc = config->crtc[0];
2820     int enabled = 0, failed = 0;
2821     int c;
2822 
2823     /* A driver with this hook will take care of this */
2824     if (!crtc->funcs->set_mode_major) {
2825         xf86PrepareOutputs(scrn);
2826         xf86PrepareCrtcs(scrn);
2827     }
2828 
2829     for (c = 0; c < config->num_crtc; c++) {
2830         xf86OutputPtr output = NULL;
2831         int o;
2832         RRTransformPtr transform;
2833 
2834         crtc = config->crtc[c];
2835 
2836         /* Skip disabled CRTCs */
2837         if (!crtc->enabled)
2838             continue;
2839 
2840         if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc)
2841             output = xf86CompatOutput(scrn);
2842         else {
2843             for (o = 0; o < config->num_output; o++)
2844                 if (config->output[o]->crtc == crtc) {
2845                     output = config->output[o];
2846                     break;
2847                 }
2848         }
2849         /* paranoia */
2850         if (!output)
2851             continue;
2852 
2853         /* Mark that we'll need to re-set the mode for sure */
2854         memset(&crtc->mode, 0, sizeof(crtc->mode));
2855         if (!crtc->desiredMode.CrtcHDisplay) {
2856             DisplayModePtr mode =
2857                 xf86OutputFindClosestMode(output, scrn->currentMode);
2858 
2859             if (!mode)
2860                 return FALSE;
2861             xf86SaveModeContents(&crtc->desiredMode, mode);
2862             crtc->desiredRotation = RR_Rotate_0;
2863             crtc->desiredTransformPresent = FALSE;
2864             crtc->desiredX = 0;
2865             crtc->desiredY = 0;
2866         }
2867 
2868         if (crtc->desiredTransformPresent)
2869             transform = &crtc->desiredTransform;
2870         else
2871             transform = NULL;
2872         if (xf86CrtcSetModeTransform
2873             (crtc, &crtc->desiredMode, crtc->desiredRotation, transform,
2874              crtc->desiredX, crtc->desiredY)) {
2875             ++enabled;
2876         } else {
2877             for (o = 0; o < config->num_output; o++)
2878                 if (config->output[o]->crtc == crtc)
2879                     config->output[o]->crtc = NULL;
2880             crtc->enabled = FALSE;
2881             ++failed;
2882 	}
2883     }
2884 
2885     xf86DisableUnusedFunctions(scrn);
2886     return enabled != 0 || failed == 0;
2887 }
2888 
2889 /**
2890  * In the current world order, there are lists of modes per output, which may
2891  * or may not include the mode that was asked to be set by XFree86's mode
2892  * selection.  Find the closest one, in the following preference order:
2893  *
2894  * - Equality
2895  * - Closer in size to the requested mode, but no larger
2896  * - Closer in refresh rate to the requested mode.
2897  */
2898 
2899 DisplayModePtr
xf86OutputFindClosestMode(xf86OutputPtr output,DisplayModePtr desired)2900 xf86OutputFindClosestMode(xf86OutputPtr output, DisplayModePtr desired)
2901 {
2902     DisplayModePtr best = NULL, scan = NULL;
2903 
2904     for (scan = output->probed_modes; scan != NULL; scan = scan->next) {
2905         /* If there's an exact match, we're done. */
2906         if (xf86ModesEqual(scan, desired)) {
2907             best = desired;
2908             break;
2909         }
2910 
2911         /* Reject if it's larger than the desired mode. */
2912         if (scan->HDisplay > desired->HDisplay ||
2913             scan->VDisplay > desired->VDisplay) {
2914             continue;
2915         }
2916 
2917         /*
2918          * If we haven't picked a best mode yet, use the first
2919          * one in the size range
2920          */
2921         if (best == NULL) {
2922             best = scan;
2923             continue;
2924         }
2925 
2926         /* Find if it's closer to the right size than the current best
2927          * option.
2928          */
2929         if ((scan->HDisplay > best->HDisplay &&
2930              scan->VDisplay >= best->VDisplay) ||
2931             (scan->HDisplay >= best->HDisplay &&
2932              scan->VDisplay > best->VDisplay)) {
2933             best = scan;
2934             continue;
2935         }
2936 
2937         /* Find if it's still closer to the right refresh than the current
2938          * best resolution.
2939          */
2940         if (scan->HDisplay == best->HDisplay &&
2941             scan->VDisplay == best->VDisplay &&
2942             (fabs(scan->VRefresh - desired->VRefresh) <
2943              fabs(best->VRefresh - desired->VRefresh))) {
2944             best = scan;
2945         }
2946     }
2947     return best;
2948 }
2949 
2950 /**
2951  * When setting a mode through XFree86-VidModeExtension or XFree86-DGA,
2952  * take the specified mode and apply it to the crtc connected to the compat
2953  * output. Then, find similar modes for the other outputs, as with the
2954  * InitialConfiguration code above. The goal is to clone the desired
2955  * mode across all outputs that are currently active.
2956  */
2957 
2958 Bool
xf86SetSingleMode(ScrnInfoPtr pScrn,DisplayModePtr desired,Rotation rotation)2959 xf86SetSingleMode(ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation)
2960 {
2961     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2962     Bool ok = TRUE;
2963     xf86OutputPtr compat_output;
2964     DisplayModePtr compat_mode = NULL;
2965     int c;
2966 
2967     /*
2968      * Let the compat output drive the final mode selection
2969      */
2970     compat_output = xf86CompatOutput(pScrn);
2971     if (compat_output)
2972         compat_mode = xf86OutputFindClosestMode(compat_output, desired);
2973     if (compat_mode)
2974         desired = compat_mode;
2975 
2976     for (c = 0; c < config->num_crtc; c++) {
2977         xf86CrtcPtr crtc = config->crtc[c];
2978         DisplayModePtr crtc_mode = NULL;
2979         int o;
2980 
2981         if (!crtc->enabled)
2982             continue;
2983 
2984         for (o = 0; o < config->num_output; o++) {
2985             xf86OutputPtr output = config->output[o];
2986             DisplayModePtr output_mode;
2987 
2988             /* skip outputs not on this crtc */
2989             if (output->crtc != crtc)
2990                 continue;
2991 
2992             if (crtc_mode) {
2993                 output_mode = xf86OutputFindClosestMode(output, crtc_mode);
2994                 if (output_mode != crtc_mode)
2995                     output->crtc = NULL;
2996             }
2997             else
2998                 crtc_mode = xf86OutputFindClosestMode(output, desired);
2999         }
3000         if (!crtc_mode) {
3001             crtc->enabled = FALSE;
3002             continue;
3003         }
3004         if (!xf86CrtcSetModeTransform(crtc, crtc_mode, rotation, NULL, 0, 0))
3005             ok = FALSE;
3006         else {
3007             xf86SaveModeContents(&crtc->desiredMode, crtc_mode);
3008             crtc->desiredRotation = rotation;
3009             crtc->desiredTransformPresent = FALSE;
3010             crtc->desiredX = 0;
3011             crtc->desiredY = 0;
3012         }
3013     }
3014     xf86DisableUnusedFunctions(pScrn);
3015 #ifdef RANDR_12_INTERFACE
3016     xf86RandR12TellChanged(pScrn->pScreen);
3017 #endif
3018     return ok;
3019 }
3020 
3021 /**
3022  * Set the DPMS power mode of all outputs and CRTCs.
3023  *
3024  * If the new mode is off, it will turn off outputs and then CRTCs.
3025  * Otherwise, it will affect CRTCs before outputs.
3026  */
3027 void
xf86DPMSSet(ScrnInfoPtr scrn,int mode,int flags)3028 xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags)
3029 {
3030     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3031     int i;
3032 
3033     if (!scrn->vtSema)
3034         return;
3035 
3036     if (mode == DPMSModeOff) {
3037         for (i = 0; i < config->num_output; i++) {
3038             xf86OutputPtr output = config->output[i];
3039 
3040             if (!xf86OutputIsLeased(output) && output->crtc != NULL)
3041                 (*output->funcs->dpms) (output, mode);
3042         }
3043     }
3044 
3045     for (i = 0; i < config->num_crtc; i++) {
3046         xf86CrtcPtr crtc = config->crtc[i];
3047 
3048         if (crtc->enabled)
3049             (*crtc->funcs->dpms) (crtc, mode);
3050     }
3051 
3052     if (mode != DPMSModeOff) {
3053         for (i = 0; i < config->num_output; i++) {
3054             xf86OutputPtr output = config->output[i];
3055 
3056             if (!xf86OutputIsLeased(output) && output->crtc != NULL)
3057                 (*output->funcs->dpms) (output, mode);
3058         }
3059     }
3060 }
3061 
3062 /**
3063  * Implement the screensaver by just calling down into the driver DPMS hooks.
3064  *
3065  * Even for monitors with no DPMS support, by the definition of our DPMS hooks,
3066  * the outputs will still get disabled (blanked).
3067  */
3068 Bool
xf86SaveScreen(ScreenPtr pScreen,int mode)3069 xf86SaveScreen(ScreenPtr pScreen, int mode)
3070 {
3071     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
3072 
3073     if (xf86IsUnblank(mode))
3074         xf86DPMSSet(pScrn, DPMSModeOn, 0);
3075     else
3076         xf86DPMSSet(pScrn, DPMSModeOff, 0);
3077 
3078     return TRUE;
3079 }
3080 
3081 /**
3082  * Disable all inactive crtcs and outputs
3083  */
3084 void
xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)3085 xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)
3086 {
3087     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3088     int o, c;
3089 
3090     for (o = 0; o < xf86_config->num_output; o++) {
3091         xf86OutputPtr output = xf86_config->output[o];
3092 
3093         if (!output->crtc)
3094             (*output->funcs->dpms) (output, DPMSModeOff);
3095     }
3096 
3097     for (c = 0; c < xf86_config->num_crtc; c++) {
3098         xf86CrtcPtr crtc = xf86_config->crtc[c];
3099 
3100         if (!crtc->enabled) {
3101             xf86DisableCrtc(crtc);
3102             memset(&crtc->mode, 0, sizeof(crtc->mode));
3103             xf86RotateDestroy(crtc);
3104             crtc->active = FALSE;
3105         }
3106     }
3107     if (pScrn->pScreen)
3108         xf86_crtc_notify(pScrn->pScreen);
3109     if (pScrn->ModeSet)
3110         pScrn->ModeSet(pScrn);
3111     if (pScrn->pScreen) {
3112         if (pScrn->pScreen->isGPU)
3113             xf86CursorResetCursor(pScrn->pScreen->current_primary);
3114         else
3115             xf86CursorResetCursor(pScrn->pScreen);
3116     }
3117 }
3118 
3119 #ifdef RANDR_12_INTERFACE
3120 
3121 #define EDID_ATOM_NAME		"EDID"
3122 
3123 /**
3124  * Set the RandR EDID property
3125  */
3126 static void
xf86OutputSetEDIDProperty(xf86OutputPtr output,void * data,int data_len)3127 xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len)
3128 {
3129     Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE);
3130 
3131     /* This may get called before the RandR resources have been created */
3132     if (output->randr_output == NULL)
3133         return;
3134 
3135     if (data_len != 0) {
3136         RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
3137                                PropModeReplace, data_len, data, FALSE, TRUE);
3138     }
3139     else {
3140         RRDeleteOutputProperty(output->randr_output, edid_atom);
3141     }
3142 }
3143 
3144 #define TILE_ATOM_NAME		"TILE"
3145 /* changing this in the future could be tricky as people may hardcode 8 */
3146 #define TILE_PROP_NUM_ITEMS		8
3147 static void
xf86OutputSetTileProperty(xf86OutputPtr output)3148 xf86OutputSetTileProperty(xf86OutputPtr output)
3149 {
3150     Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE);
3151 
3152     /* This may get called before the RandR resources have been created */
3153     if (output->randr_output == NULL)
3154         return;
3155 
3156     if (output->tile_info.group_id != 0) {
3157         RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32,
3158                                PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE);
3159     }
3160     else {
3161         RRDeleteOutputProperty(output->randr_output, tile_atom);
3162     }
3163 }
3164 
3165 #endif
3166 
3167 /* Pull out a physical size from a detailed timing if available. */
3168 struct det_phySize_parameter {
3169     xf86OutputPtr output;
3170     ddc_quirk_t quirks;
3171     Bool ret;
3172 };
3173 
3174 static void
handle_detailed_physical_size(struct detailed_monitor_section * det_mon,void * data)3175 handle_detailed_physical_size(struct detailed_monitor_section
3176                               *det_mon, void *data)
3177 {
3178     struct det_phySize_parameter *p;
3179 
3180     p = (struct det_phySize_parameter *) data;
3181 
3182     if (p->ret == TRUE)
3183         return;
3184 
3185     xf86DetTimingApplyQuirks(det_mon, p->quirks,
3186                              p->output->MonInfo->features.hsize,
3187                              p->output->MonInfo->features.vsize);
3188     if (det_mon->type == DT &&
3189         det_mon->section.d_timings.h_size != 0 &&
3190         det_mon->section.d_timings.v_size != 0) {
3191         /* some sanity checking for aspect ratio:
3192            assume any h / v (or v / h) > 2.4 to be bogus.
3193            This would even include cinemascope */
3194         if (((det_mon->section.d_timings.h_size * 5) <
3195              (det_mon->section.d_timings.v_size * 12)) &&
3196             ((det_mon->section.d_timings.v_size * 5) <
3197              (det_mon->section.d_timings.h_size * 12))) {
3198             p->output->mm_width = det_mon->section.d_timings.h_size;
3199             p->output->mm_height = det_mon->section.d_timings.v_size;
3200             p->ret = TRUE;
3201         } else
3202             xf86DrvMsg(p->output->scrn->scrnIndex, X_WARNING,
3203                        "Output %s: Strange aspect ratio (%i/%i), "
3204                        "consider adding a quirk\n", p->output->name,
3205                        det_mon->section.d_timings.h_size,
3206                        det_mon->section.d_timings.v_size);
3207     }
3208 }
3209 
3210 Bool
xf86OutputParseKMSTile(const char * tile_data,int tile_length,struct xf86CrtcTileInfo * tile_info)3211 xf86OutputParseKMSTile(const char *tile_data, int tile_length,
3212                        struct xf86CrtcTileInfo *tile_info)
3213 {
3214     int ret;
3215 
3216     ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d",
3217                  &tile_info->group_id,
3218                  &tile_info->flags,
3219                  &tile_info->num_h_tile,
3220                  &tile_info->num_v_tile,
3221                  &tile_info->tile_h_loc,
3222                  &tile_info->tile_v_loc,
3223                  &tile_info->tile_h_size,
3224                  &tile_info->tile_v_size);
3225     if (ret != 8)
3226         return FALSE;
3227     return TRUE;
3228 }
3229 
3230 void
xf86OutputSetTile(xf86OutputPtr output,struct xf86CrtcTileInfo * tile_info)3231 xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info)
3232 {
3233     if (tile_info)
3234         output->tile_info = *tile_info;
3235     else
3236         memset(&output->tile_info, 0, sizeof(output->tile_info));
3237 #ifdef RANDR_12_INTERFACE
3238     xf86OutputSetTileProperty(output);
3239 #endif
3240 }
3241 
3242 /**
3243  * Set the EDID information for the specified output
3244  */
3245 void
xf86OutputSetEDID(xf86OutputPtr output,xf86MonPtr edid_mon)3246 xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon)
3247 {
3248     ScrnInfoPtr scrn = output->scrn;
3249     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3250     Bool debug_modes = config->debug_modes || xf86Initialising;
3251 
3252 #ifdef RANDR_12_INTERFACE
3253     int size;
3254 #endif
3255 
3256     free(output->MonInfo);
3257 
3258     output->MonInfo = edid_mon;
3259     output->mm_width = 0;
3260     output->mm_height = 0;
3261 
3262     if (debug_modes) {
3263         xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n",
3264                    output->name);
3265         xf86PrintEDID(edid_mon);
3266     }
3267 
3268     /* Set the DDC properties for the 'compat' output */
3269     /* GPU screens don't have a root window */
3270     if (output == xf86CompatOutput(scrn) && !scrn->is_gpu)
3271         xf86SetDDCproperties(scrn, edid_mon);
3272 
3273 #ifdef RANDR_12_INTERFACE
3274     /* Set the RandR output properties */
3275     size = 0;
3276     if (edid_mon) {
3277         if (edid_mon->ver.version == 1) {
3278             size = 128;
3279             if (edid_mon->flags & EDID_COMPLETE_RAWDATA)
3280                 size += edid_mon->no_sections * 128;
3281         }
3282         else if (edid_mon->ver.version == 2)
3283             size = 256;
3284     }
3285     xf86OutputSetEDIDProperty(output, edid_mon ? edid_mon->rawData : NULL,
3286                               size);
3287 #endif
3288 
3289     if (edid_mon) {
3290 
3291         struct det_phySize_parameter p;
3292 
3293         p.output = output;
3294         p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex, edid_mon, FALSE);
3295         p.ret = FALSE;
3296         xf86ForEachDetailedBlock(edid_mon, handle_detailed_physical_size, &p);
3297 
3298         /* if no mm size is available from a detailed timing, check the max size field */
3299         if ((!output->mm_width || !output->mm_height) &&
3300             (edid_mon->features.hsize && edid_mon->features.vsize)) {
3301             output->mm_width = edid_mon->features.hsize * 10;
3302             output->mm_height = edid_mon->features.vsize * 10;
3303         }
3304     }
3305 }
3306 
3307 /**
3308  * Return the list of modes supported by the EDID information
3309  * stored in 'output'
3310  */
3311 DisplayModePtr
xf86OutputGetEDIDModes(xf86OutputPtr output)3312 xf86OutputGetEDIDModes(xf86OutputPtr output)
3313 {
3314     ScrnInfoPtr scrn = output->scrn;
3315     xf86MonPtr edid_mon = output->MonInfo;
3316 
3317     if (!edid_mon)
3318         return NULL;
3319     return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
3320 }
3321 
3322 /* maybe we should care about DDC1?  meh. */
3323 xf86MonPtr
xf86OutputGetEDID(xf86OutputPtr output,I2CBusPtr pDDCBus)3324 xf86OutputGetEDID(xf86OutputPtr output, I2CBusPtr pDDCBus)
3325 {
3326     ScrnInfoPtr scrn = output->scrn;
3327     xf86MonPtr mon;
3328 
3329     mon = xf86DoEEDID(scrn, pDDCBus, TRUE);
3330     if (mon)
3331         xf86DDCApplyQuirks(scrn->scrnIndex, mon);
3332 
3333     return mon;
3334 }
3335 
3336 static const char *_xf86ConnectorNames[] = {
3337     "None", "VGA", "DVI-I", "DVI-D",
3338     "DVI-A", "Composite", "S-Video",
3339     "Component", "LFP", "Proprietary",
3340     "HDMI", "DisplayPort",
3341 };
3342 
3343 const char *
xf86ConnectorGetName(xf86ConnectorType connector)3344 xf86ConnectorGetName(xf86ConnectorType connector)
3345 {
3346     return _xf86ConnectorNames[connector];
3347 }
3348 
3349 #ifdef XV
3350 static void
x86_crtc_box_intersect(BoxPtr dest,BoxPtr a,BoxPtr b)3351 x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
3352 {
3353     dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
3354     dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
3355     dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
3356     dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
3357 
3358     if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
3359         dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
3360 }
3361 
3362 static void
x86_crtc_box(xf86CrtcPtr crtc,BoxPtr crtc_box)3363 x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
3364 {
3365     if (crtc->enabled) {
3366         crtc_box->x1 = crtc->x;
3367         crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
3368         crtc_box->y1 = crtc->y;
3369         crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
3370     }
3371     else
3372         crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
3373 }
3374 
3375 static int
xf86_crtc_box_area(BoxPtr box)3376 xf86_crtc_box_area(BoxPtr box)
3377 {
3378     return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
3379 }
3380 
3381 /*
3382  * Return the crtc covering 'box'. If two crtcs cover a portion of
3383  * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
3384  * with greater coverage
3385  */
3386 
3387 static xf86CrtcPtr
xf86_covering_crtc(ScrnInfoPtr pScrn,BoxPtr box,xf86CrtcPtr desired,BoxPtr crtc_box_ret)3388 xf86_covering_crtc(ScrnInfoPtr pScrn,
3389                    BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
3390 {
3391     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3392     xf86CrtcPtr crtc, best_crtc;
3393     int coverage, best_coverage;
3394     int c;
3395     BoxRec crtc_box, cover_box;
3396 
3397     best_crtc = NULL;
3398     best_coverage = 0;
3399     crtc_box_ret->x1 = 0;
3400     crtc_box_ret->x2 = 0;
3401     crtc_box_ret->y1 = 0;
3402     crtc_box_ret->y2 = 0;
3403     for (c = 0; c < xf86_config->num_crtc; c++) {
3404         crtc = xf86_config->crtc[c];
3405         x86_crtc_box(crtc, &crtc_box);
3406         x86_crtc_box_intersect(&cover_box, &crtc_box, box);
3407         coverage = xf86_crtc_box_area(&cover_box);
3408         if (coverage && crtc == desired) {
3409             *crtc_box_ret = crtc_box;
3410             return crtc;
3411         }
3412         else if (coverage > best_coverage) {
3413             *crtc_box_ret = crtc_box;
3414             best_crtc = crtc;
3415             best_coverage = coverage;
3416         }
3417     }
3418     return best_crtc;
3419 }
3420 
3421 /*
3422  * For overlay video, compute the relevant CRTC and
3423  * clip video to that.
3424  *
3425  * returning FALSE means there was a memory failure of some kind,
3426  * not that the video shouldn't be displayed
3427  */
3428 
3429 Bool
xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn,xf86CrtcPtr * crtc_ret,xf86CrtcPtr desired_crtc,BoxPtr dst,INT32 * xa,INT32 * xb,INT32 * ya,INT32 * yb,RegionPtr reg,INT32 width,INT32 height)3430 xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn,
3431                             xf86CrtcPtr * crtc_ret,
3432                             xf86CrtcPtr desired_crtc,
3433                             BoxPtr dst,
3434                             INT32 *xa,
3435                             INT32 *xb,
3436                             INT32 *ya,
3437                             INT32 *yb, RegionPtr reg, INT32 width, INT32 height)
3438 {
3439     Bool ret;
3440     RegionRec crtc_region_local;
3441     RegionPtr crtc_region = reg;
3442 
3443     if (crtc_ret) {
3444         BoxRec crtc_box;
3445         xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst,
3446                                               desired_crtc,
3447                                               &crtc_box);
3448 
3449         if (crtc) {
3450             RegionInit(&crtc_region_local, &crtc_box, 1);
3451             crtc_region = &crtc_region_local;
3452             RegionIntersect(crtc_region, crtc_region, reg);
3453         }
3454         *crtc_ret = crtc;
3455     }
3456 
3457     ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb,
3458                                 crtc_region, width, height);
3459 
3460     if (crtc_region != reg)
3461         RegionUninit(&crtc_region_local);
3462 
3463     return ret;
3464 }
3465 #endif
3466 
3467 xf86_crtc_notify_proc_ptr
xf86_wrap_crtc_notify(ScreenPtr screen,xf86_crtc_notify_proc_ptr new)3468 xf86_wrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr new)
3469 {
3470     if (xf86CrtcConfigPrivateIndex != -1) {
3471         ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3472         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3473         xf86_crtc_notify_proc_ptr old;
3474 
3475         old = config->xf86_crtc_notify;
3476         config->xf86_crtc_notify = new;
3477         return old;
3478     }
3479     return NULL;
3480 }
3481 
3482 void
xf86_unwrap_crtc_notify(ScreenPtr screen,xf86_crtc_notify_proc_ptr old)3483 xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old)
3484 {
3485     if (xf86CrtcConfigPrivateIndex != -1) {
3486         ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3487         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3488 
3489         config->xf86_crtc_notify = old;
3490     }
3491 }
3492 
3493 void
xf86_crtc_notify(ScreenPtr screen)3494 xf86_crtc_notify(ScreenPtr screen)
3495 {
3496     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3497     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3498 
3499     if (config->xf86_crtc_notify)
3500         config->xf86_crtc_notify(screen);
3501 }
3502 
3503 Bool
xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)3504 xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
3505 {
3506     if (xf86CrtcConfigPrivateIndex != -1) {
3507         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3508         xf86CrtcPtr crtc;
3509 
3510         /* for multiple drivers loaded we need this */
3511         if (!xf86_config)
3512             return FALSE;
3513         if (xf86_config->num_crtc == 0)
3514             return FALSE;
3515         crtc = xf86_config->crtc[0];
3516 
3517         return crtc->funcs->gamma_set != NULL;
3518     }
3519 
3520     return FALSE;
3521 }
3522 
3523 void
xf86ProviderSetup(ScrnInfoPtr scrn,const xf86ProviderFuncsRec * funcs,const char * name)3524 xf86ProviderSetup(ScrnInfoPtr scrn,
3525                   const xf86ProviderFuncsRec *funcs, const char *name)
3526 {
3527     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3528 
3529     assert(!xf86_config->name);
3530     assert(name);
3531 
3532     xf86_config->name = strdup(name);
3533     xf86_config->provider_funcs = funcs;
3534 #ifdef RANDR_12_INTERFACE
3535     xf86_config->randr_provider = NULL;
3536 #endif
3537 }
3538 
3539 void
xf86DetachAllCrtc(ScrnInfoPtr scrn)3540 xf86DetachAllCrtc(ScrnInfoPtr scrn)
3541 {
3542         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3543         int i;
3544 
3545         for (i = 0; i < xf86_config->num_crtc; i++) {
3546             xf86CrtcPtr crtc = xf86_config->crtc[i];
3547 
3548             if (crtc->randr_crtc)
3549                 RRCrtcDetachScanoutPixmap(crtc->randr_crtc);
3550 
3551             /* dpms off */
3552             xf86DisableCrtc(crtc);
3553             /* force a reset the next time its used */
3554             crtc->randr_crtc->mode = NULL;
3555             crtc->mode.HDisplay = 0;
3556             crtc->x = crtc->y = 0;
3557         }
3558 }
3559