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