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