diff options
author | Dave Airlie <airlied@linux.ie> | 2007-01-04 12:29:51 +1100 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2007-01-04 12:29:51 +1100 |
commit | a43c1d55f5f855d9e6ae939dd4eec1c607b6d514 (patch) | |
tree | 3eb7861c6a9d2a1297d780bdceeaa46c6690e9cd /src/radeon_xf86Crtc.c | |
parent | 87592ffb717da1f0a1767a38918d16d60953599c (diff) |
bring radeon randr code inline with intel randr code
Diffstat (limited to 'src/radeon_xf86Crtc.c')
-rw-r--r-- | src/radeon_xf86Crtc.c | 787 |
1 files changed, 709 insertions, 78 deletions
diff --git a/src/radeon_xf86Crtc.c b/src/radeon_xf86Crtc.c index 76b03f5c..7414d34d 100644 --- a/src/radeon_xf86Crtc.c +++ b/src/radeon_xf86Crtc.c @@ -5,21 +5,21 @@ * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H @@ -34,10 +34,12 @@ #include "xf86DDC.h" //#include "i.h" #include "radeon_xf86Crtc.h" +#include "radeon_xf86Modes.h" #include "X11/extensions/render.h" #define DPMS_SERVER #include "X11/extensions/dpms.h" +#include "X11/Xatom.h" /* * Initialize xf86CrtcConfig structure @@ -124,6 +126,79 @@ xf86CrtcDestroy (xf86CrtcPtr crtc) /* * Output functions */ + +extern XF86ConfigPtr xf86configptr; + +typedef enum { + OPTION_PREFERRED_MODE, + OPTION_POSITION, + OPTION_BELOW, + OPTION_RIGHT_OF, + OPTION_ABOVE, + OPTION_LEFT_OF, + OPTION_ENABLE, + OPTION_DISABLE, + OPTION_MIN_CLOCK, + OPTION_MAX_CLOCK, +} OutputOpts; + +static OptionInfoRec xf86OutputOptions[] = { + {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, + {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, + {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, + {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, + {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static void +xf86OutputSetMonitor (xf86OutputPtr output) +{ + char *option_name; + static const char monitor_prefix[] = "monitor-"; + char *monitor; + + if (output->options) + xfree (output->options); + + output->options = xnfalloc (sizeof (xf86OutputOptions)); + memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); + + option_name = xnfalloc (strlen (monitor_prefix) + + strlen (output->name) + 1); + strcpy (option_name, monitor_prefix); + strcat (option_name, output->name); + monitor = xf86findOptionValue (output->scrn->options, option_name); + if (!monitor) + monitor = output->name; + else + xf86MarkOptionUsedByName (output->scrn->options, option_name); + xfree (option_name); + output->conf_monitor = xf86findMonitor (monitor, + xf86configptr->conf_monitor_lst); + if (output->conf_monitor) + xf86ProcessOptions (output->scrn->scrnIndex, + output->conf_monitor->mon_option_lst, + output->options); +} + +static Bool +xf86OutputEnabled (xf86OutputPtr output) +{ + /* Check to see if this output was disabled in the config file */ + if (xf86ReturnOptValBool (output->options, OPTION_ENABLE, TRUE) == FALSE || + xf86ReturnOptValBool (output->options, OPTION_DISABLE, FALSE) == TRUE) + { + return FALSE; + } + return TRUE; +} + xf86OutputPtr xf86OutputCreate (ScrnInfoPtr scrn, const xf86OutputFuncsRec *funcs, @@ -144,6 +219,8 @@ xf86OutputCreate (ScrnInfoPtr scrn, #ifdef RANDR_12_INTERFACE output->randr_output = NULL; #endif + xf86OutputSetMonitor (output); + if (xf86_config->output) outputs = xrealloc (xf86_config->output, (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); @@ -154,24 +231,28 @@ xf86OutputCreate (ScrnInfoPtr scrn, xfree (output); return NULL; } + xf86_config->output = outputs; xf86_config->output[xf86_config->num_output++] = output; + return output; } -void +Bool xf86OutputRename (xf86OutputPtr output, const char *name) { int len = strlen(name); char *newname = xalloc (len + 1); if (!newname) - return; /* so sorry... */ + return FALSE; /* so sorry... */ strcpy (newname, name); if (output->name != (char *) (output + 1)) xfree (output->name); output->name = newname; + xf86OutputSetMonitor (output); + return TRUE; } void @@ -348,7 +429,9 @@ xf86PickCrtcs (ScrnInfoPtr pScrn, * If the two outputs desire the same mode, * see if they can be cloned */ - if (xf86ModesEqual (modes[o], modes[n])) + if (xf86ModesEqual (modes[o], modes[n]) && + config->output[o]->initial_x == config->output[n]->initial_x && + config->output[o]->initial_y == config->output[n]->initial_y) { for (l = 0; l < config->num_output; l++) if (output->possible_clones & (1 << l)) @@ -362,7 +445,7 @@ xf86PickCrtcs (ScrnInfoPtr pScrn, crtcs[n] = crtc; memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); score = my_score + xf86PickCrtcs (pScrn, crtcs, modes, n+1, width, height); - if (score >= best_score) + if (score > best_score) { best_crtc = crtc; best_score = score; @@ -376,7 +459,8 @@ xf86PickCrtcs (ScrnInfoPtr pScrn, /* * Compute the virtual size necessary to place all of the available - * crtcs in a panorama configuration + * crtcs in the specified configuration and also large enough to + * resize any crtc to the largest available mode */ static void @@ -391,7 +475,13 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp) for (c = 0; c < config->num_crtc; c++) { int crtc_width = 0, crtc_height = 0; + xf86CrtcPtr crtc = config->crtc[c]; + if (crtc->enabled) + { + crtc_width = crtc->x + crtc->desiredMode.HDisplay; + crtc_height = crtc->y + crtc->desiredMode.VDisplay; + } for (o = 0; o < config->num_output; o++) { xf86OutputPtr output = config->output[o]; @@ -409,7 +499,8 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp) } } } - width += crtc_width; + if (crtc_width > width) + width = crtc_width; if (crtc_height > height) height = crtc_height; } @@ -421,6 +512,186 @@ xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp) *heightp = height; } +#define POSITION_UNSET -100000 + +static Bool +xf86InitialOutputPositions (ScrnInfoPtr pScrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + int min_x, min_y; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x = output->initial_y = POSITION_UNSET; + } + + /* + * Loop until all outputs are set + */ + for (;;) + { + Bool any_set = FALSE; + Bool keep_going = FALSE; + + for (o = 0; o < config->num_output; o++) + { + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + xf86OutputPtr output = config->output[o]; + xf86OutputPtr relative; + char *relative_name; + char *position; + OutputOpts relation; + int r; + + if (output->initial_x != POSITION_UNSET) + continue; + position = xf86GetOptValString (output->options, + OPTION_POSITION); + /* + * Absolute position wins + */ + if (position) + { + int x, y; + if (sscanf (position, "%d %d", &x, &y) == 2) + { + output->initial_x = x; + output->initial_y = y; + } + else + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Output %s position not of form \"x y\"\n", + output->name); + output->initial_x = output->initial_y = 0; + } + any_set = TRUE; + continue; + } + /* + * Next comes relative positions + */ + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + { + int or; + relative = NULL; + for (or = 0; or < config->num_output; or++) + { + xf86OutputPtr out_rel = config->output[or]; + XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; + char *name; + + if (rel_mon) + name = rel_mon->mon_identifier; + else + name = out_rel->name; + if (!strcmp (relative_name, name)) + { + relative = config->output[or]; + break; + } + } + if (!relative) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to unknown output %s\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (relative->initial_x == POSITION_UNSET) + { + keep_going = TRUE; + continue; + } + output->initial_x = relative->initial_x; + output->initial_y = relative->initial_y; + switch (relation) { + case OPTION_BELOW: + output->initial_y += modes[or]->VDisplay; + break; + case OPTION_RIGHT_OF: + output->initial_x += modes[or]->HDisplay; + break; + case OPTION_ABOVE: + output->initial_y -= modes[o]->VDisplay; + break; + case OPTION_LEFT_OF: + output->initial_x -= modes[o]->HDisplay; + break; + default: + break; + } + any_set = TRUE; + continue; + } + + /* Nothing set, just stick them at 0,0 */ + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + } + if (!keep_going) + break; + if (!any_set) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->initial_x == POSITION_UNSET) + { + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "Output position loop. Moving %s to 0,0\n", + output->name); + output->initial_x = output->initial_y = 0; + break; + } + } + } + } + + /* + * normalize positions + */ + min_x = 1000000; + min_y = 1000000; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->initial_x < min_x) + min_x = output->initial_x; + if (output->initial_y < min_y) + min_y = output->initial_y; + } + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x -= min_x; + output->initial_y -= min_y; + } + return TRUE; +} + /* * XXX walk the monitor mode list and prune out duplicates that * are inserted by xf86DDCMonitorSet. In an ideal world, that @@ -440,39 +711,270 @@ xf86PruneDuplicateMonitorModes (MonPtr Monitor) { next = clone->next; if (xf86ModesEqual (master, clone)) + { + if (Monitor->Last == clone) + Monitor->Last = clone->prev; xf86DeleteMode (&Monitor->Modes, clone); + } + } + } +} + +/** Return - 0 + if a should be earlier, same or later than b in list + */ +static int +i830xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) +{ + int diff; + + diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); + if (diff) + return diff; + diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; + if (diff) + return diff; + diff = b->Clock - a->Clock; + return diff; +} + +/** + * Insertion sort input in-place and return the resulting head + */ +static DisplayModePtr +i830xf86SortModes (DisplayModePtr input) +{ + DisplayModePtr output = NULL, i, o, n, *op, prev; + + /* sort by preferred status and pixel area */ + while (input) + { + i = input; + input = input->next; + for (op = &output; (o = *op); op = &o->next) + if (i830xf86ModeCompare (o, i) > 0) + break; + i->next = *op; + *op = i; + } + /* prune identical modes */ + for (o = output; o && (n = o->next); o = n) + { + if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) + { + o->next = n->next; + xfree (n->name); + xfree (n); + n = o; } } + /* hook up backward links */ + prev = NULL; + for (o = output; o; o = o->next) + { + o->prev = prev; + prev = o; + } + return output; } +#define DEBUG_REPROBE 1 + void -xf86ProbeOutputModes (ScrnInfoPtr pScrn) +xf86ProbeOutputModes (ScrnInfoPtr pScrn, int maxX, int maxY) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); - Bool properties_set = FALSE; int o; + if (maxX == 0 || maxY == 0) + xf86RandR12GetOriginalVirtualSize (pScrn, &maxX, &maxY); + /* Elide duplicate modes before defaulting code uses them */ xf86PruneDuplicateMonitorModes (pScrn->monitor); /* Probe the list of modes for each output. */ for (o = 0; o < config->num_output; o++) { - xf86OutputPtr output = config->output[o]; - DisplayModePtr mode; - + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + DisplayModePtr config_modes = NULL, output_modes, default_modes; + char *preferred_mode; + xf86MonPtr edid_monitor; + XF86ConfMonitorPtr conf_monitor; + MonRec mon_rec; + int min_clock = 0; + int max_clock = 0; + double clock; + enum { sync_config, sync_edid, sync_default } sync_source = sync_default; + while (output->probed_modes != NULL) xf86DeleteMode(&output->probed_modes, output->probed_modes); - output->probed_modes = (*output->funcs->get_modes) (output); + /* + * Check connection status + */ + output->status = (*output->funcs->detect)(output); - /* Set the DDC properties to whatever first output has DDC information. + if (output->status == XF86OutputStatusDisconnected) + continue; + + memset (&mon_rec, '\0', sizeof (mon_rec)); + + conf_monitor = output->conf_monitor; + + if (conf_monitor) + { + int i; + + for (i = 0; i < conf_monitor->mon_n_hsync; i++) + { + mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; + mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; + mon_rec.nHsync++; + sync_source = sync_config; + } + for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; + mon_rec.nVrefresh++; + sync_source = sync_config; + } + config_modes = i830xf86GetMonitorModes (pScrn, conf_monitor); + } + + output_modes = (*output->funcs->get_modes) (output); + + edid_monitor = output->MonInfo; + + if (edid_monitor) + { + int i; + Bool set_hsync = mon_rec.nHsync == 0; + Bool set_vrefresh = mon_rec.nVrefresh == 0; + + for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++) + { + if (edid_monitor->det_mon[i].type == DS_RANGES) + { + struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges; + if (set_hsync && ranges->max_h) + { + mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h; + mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h; + mon_rec.nHsync++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (set_vrefresh && ranges->max_v) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v; + mon_rec.nVrefresh++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (ranges->max_clock > max_clock) + max_clock = ranges->max_clock; + } + } + } + + if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, + OPTUNITS_KHZ, &clock)) + min_clock = (int) clock; + if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, + OPTUNITS_KHZ, &clock)) + max_clock = (int) clock; + + /* + * These limits will end up setting a 1024x768@60Hz mode by default, + * which seems like a fairly good mode to use when nothing else is + * specified */ - if (output->MonInfo != NULL && !properties_set) { - xf86SetDDCproperties(pScrn, output->MonInfo); - properties_set = TRUE; + if (mon_rec.nHsync == 0) + { + mon_rec.hsync[0].lo = 31.0; + mon_rec.hsync[0].hi = 55.0; + mon_rec.nHsync = 1; + } + if (mon_rec.nVrefresh == 0) + { + mon_rec.vrefresh[0].lo = 58.0; + mon_rec.vrefresh[0].hi = 62.0; + mon_rec.nVrefresh = 1; } + default_modes = RADEONxf86GetDefaultModes (output->interlaceAllowed, + output->doubleScanAllowed); + + if (sync_source == sync_config) + { + /* + * Check output and config modes against sync range from config file + */ + RADEONxf86ValidateModesSync (pScrn, output_modes, &mon_rec); + RADEONxf86ValidateModesSync (pScrn, config_modes, &mon_rec); + } + /* + * Check default modes against sync range + */ + RADEONxf86ValidateModesSync (pScrn, default_modes, &mon_rec); + /* + * Check default modes against monitor max clock + */ + if (max_clock) + RADEONxf86ValidateModesClocks(pScrn, default_modes, + &min_clock, &max_clock, 1); + + output->probed_modes = NULL; + output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); + + /* + * Check all modes against max size + */ + if (maxX && maxY) + RADEONxf86ValidateModesSize (pScrn, output->probed_modes, + maxX, maxY, 0); + + /* + * Check all modes against output + */ + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output, mode); + + RADEONxf86PruneInvalidModes(pScrn, &output->probed_modes, TRUE); + + output->probed_modes = i830xf86SortModes (output->probed_modes); + + /* Check for a configured preference for a particular mode */ + preferred_mode = xf86GetOptValString (output->options, + OPTION_PREFERRED_MODE); + if (preferred_mode) + { + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (!strcmp (preferred_mode, mode->name)) + { + if (mode != output->probed_modes) + { + if (mode->prev) + mode->prev->next = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + mode->next = output->probed_modes; + output->probed_modes->prev = mode; + mode->prev = NULL; + output->probed_modes = mode; + } + mode->type |= M_T_PREFERRED; + break; + } + } + } + #ifdef DEBUG_REPROBE if (output->probed_modes != NULL) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -515,7 +1017,6 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn) xf86OutputPtr output; xf86CrtcPtr crtc; DisplayModePtr last, mode; - int originalVirtualX, originalVirtualY; output = config->output[config->compat_output]; if (!output->crtc) @@ -543,31 +1044,23 @@ xf86SetScrnInfoModes (ScrnInfoPtr pScrn) /* Set pScrn->modes to the mode list for the 'compat' output */ pScrn->modes = xf86DuplicateModes(pScrn, output->probed_modes); - xf86RandR12GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); - - /* Disable modes in the XFree86 DDX list that are larger than the current - * virtual size. - */ - RADEONxf86ValidateModesSize(pScrn, pScrn->modes, - originalVirtualX, originalVirtualY, - pScrn->displayWidth); - - /* Strip out anything that we threw out for virtualX/Y. */ - RADEONxf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); - for (mode = pScrn->modes; mode; mode = mode->next) if (xf86ModesEqual (mode, &crtc->desiredMode)) break; - - /* For some reason, pScrn->modes is circular, unlike the other mode lists. - * How great is that? - */ - for (last = pScrn->modes; last && last->next; last = last->next); - last->next = pScrn->modes; - pScrn->modes->prev = last; - if (mode) - while (pScrn->modes != mode) - pScrn->modes = pScrn->modes->next; + + if (pScrn->modes != NULL) { + /* For some reason, pScrn->modes is circular, unlike the other mode + * lists. How great is that? + */ + for (last = pScrn->modes; last && last->next; last = last->next) + ; + last->next = pScrn->modes; + pScrn->modes->prev = last; + if (mode) { + while (pScrn->modes != mode) + pScrn->modes = pScrn->modes->next; + } + } pScrn->currentMode = pScrn->modes; } @@ -586,35 +1079,33 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) DisplayModePtr target_mode = NULL; xf86CrtcPtr *crtcs; DisplayModePtr *modes; - int width, height; + Bool *enabled; + int width; + int height; - xf86ProbeOutputModes (pScrn); - - if (pScrn->display->virtualX == 0) - { - /* - * Expand virtual size to cover potential mode switches - */ - xf86DefaultScreenLimits (pScrn, &width, &height); - - pScrn->display->virtualX = width; - pScrn->display->virtualY = height; - } - else - { + if (pScrn->display->virtualX) width = pScrn->display->virtualX; + else + width = config->maxWidth; + if (pScrn->display->virtualY) height = pScrn->display->virtualY; - } - if (width > pScrn->virtualX) - pScrn->virtualX = width; - if (height > pScrn->virtualY) - pScrn->virtualY = height; - + else + height = config->maxHeight; + + xf86ProbeOutputModes (pScrn, width, height); + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + enabled = xnfcalloc (config->num_output, sizeof (Bool)); for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + modes[o] = NULL; + enabled[o] = (xf86OutputEnabled (output) && + output->status != XF86OutputStatusDisconnected); + } /* * Let outputs with preferred modes drive screen size @@ -623,7 +1114,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) { xf86OutputPtr output = config->output[o]; - if (output->status != XF86OutputStatusDisconnected && + if (enabled[o] && xf86OutputHasPreferredMode (output, width, height)) { target_mode = xf86DefaultMode (output, width, height); @@ -640,7 +1131,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) for (o = 0; o < config->num_output; o++) { xf86OutputPtr output = config->output[o]; - if (output->status != XF86OutputStatusDisconnected) + if (enabled[o]) { target_mode = xf86DefaultMode (output, width, height); if (target_mode) @@ -656,10 +1147,23 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) { xf86OutputPtr output = config->output[o]; - if (output->status != XF86OutputStatusDisconnected && !modes[o]) + if (enabled[o] && !modes[o]) modes[o] = xf86ClosestMode (output, target_mode, width, height); } + /* + * Set the position of each output + */ + if (!xf86InitialOutputPositions (pScrn, modes)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* + * Assign CRTCs to fit output configuration + */ if (!xf86PickCrtcs (pScrn, crtcs, modes, 0, width, height)) { xfree (crtcs); @@ -679,7 +1183,7 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) crtc->enabled = FALSE; memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); } - + /* * Set initial configuration */ @@ -693,13 +1197,28 @@ xf86InitialConfiguration (ScrnInfoPtr pScrn) { crtc->desiredMode = *mode; crtc->enabled = TRUE; - crtc->x = 0; - crtc->y = 0; + crtc->x = output->initial_x; + crtc->y = output->initial_y; output->crtc = crtc; - /* XXX set position; for now, we clone */ } } + if (pScrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover potential mode switches + */ + xf86DefaultScreenLimits (pScrn, &width, &height); + + pScrn->display->virtualX = width; + pScrn->display->virtualY = height; + } + + if (width > pScrn->virtualX) + pScrn->virtualX = width; + if (height > pScrn->virtualY) + pScrn->virtualY = height; + /* Mirror output modes to pScrn mode list */ xf86SetScrnInfoModes (pScrn); @@ -742,3 +1261,115 @@ xf86DPMSSet(ScrnInfoPtr pScrn, int mode, int flags) } } } + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID_DATA" + +/** + * Set the RandR EDID property + */ +static void +xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME), TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} + +#endif + +/** + * Set the EDID information for the specified output + */ +void +i830_xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) +{ + ScrnInfoPtr pScrn = output->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; +#ifdef RANDR_12_INTERFACE + int size; +#endif + + if (output->MonInfo != NULL) + xfree(output->MonInfo); + + output->MonInfo = edid_mon; + + /* Debug info for now, at least */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID for output %s\n", output->name); + xf86PrintEDID(edid_mon); + + /* Set the DDC properties for the 'compat' output */ + if (output == config->output[config->compat_output]) + xf86SetDDCproperties(pScrn, edid_mon); + +#ifdef RANDR_12_INTERFACE + /* Set the RandR output properties */ + size = 0; + if (edid_mon) + { + if (edid_mon->ver.version == 1) + size = 128; + else if (edid_mon->ver.version == 2) + size = 256; + } + xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); +#endif + + if (edid_mon) + { + /* Pull out a phyiscal size from a detailed timing if available. */ + for (i = 0; i < 4; i++) { + if (edid_mon->det_mon[i].type == DT && + edid_mon->det_mon[i].section.d_timings.h_size != 0 && + edid_mon->det_mon[i].section.d_timings.v_size != 0) + { + output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size; + output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size; + break; + } + } + + /* if no mm size is available from a detailed timing, check the max size field */ + if ((!output->mm_width || !output->mm_height) && + (edid_mon->features.hsize && edid_mon->features.vsize)) + { + output->mm_width = edid_mon->features.hsize * 10; + output->mm_height = edid_mon->features.vsize * 10; + } + } +} + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +DisplayModePtr +i830_xf86OutputGetEDIDModes (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + xf86MonPtr edid_mon = output->MonInfo; + + if (!edid_mon) + return NULL; + return xf86DDCGetModes(pScrn->scrnIndex, edid_mon); +} + +xf86MonPtr +i830_xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) +{ + ScrnInfoPtr pScrn = output->scrn; + + return xf86DoEDID_DDC2 (pScrn->scrnIndex, pDDCBus); +} |