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