diff --git a/src/i830.h b/src/i830.h index 27a9817b..5915a178 100644 --- a/src/i830.h +++ b/src/i830.h @@ -269,6 +269,20 @@ struct _I830OutputRec { */ enum detect_status (*detect)(ScrnInfoPtr pScrn, I830OutputPtr output); + /** + * Query the device for the modes it provides. + * + * \return singly-linked list of modes or NULL if no modes found. + */ + DisplayModePtr (*get_modes)(ScrnInfoPtr pScrn, I830OutputPtr output); + + /** + * List of available modes on this output. + * + * This should be the list from get_modes(), plus perhaps additional + * compatible modes added later. + */ + DisplayModePtr probed_modes; xf86MonPtr MonInfo; I2CBusPtr pI2CBus; I2CBusPtr pDDCBus; @@ -680,6 +694,7 @@ DisplayModePtr i830GetGTF(int h_pixels, int v_lines, float freq, /* i830_modes.c */ int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time); +DisplayModePtr i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output); /* i830_randr.c */ Bool I830RandRCreateScreenResources (ScreenPtr pScreen); diff --git a/src/i830_crt.c b/src/i830_crt.c index d271eedb..bd0099ac 100644 --- a/src/i830_crt.c +++ b/src/i830_crt.c @@ -286,6 +286,7 @@ i830_crt_init(ScrnInfoPtr pScrn) pI830->output[pI830->num_outputs].pre_set_mode = i830_crt_pre_set_mode; pI830->output[pI830->num_outputs].post_set_mode = i830_crt_post_set_mode; pI830->output[pI830->num_outputs].detect = i830_crt_detect; + pI830->output[pI830->num_outputs].get_modes = i830_ddc_get_modes; /* Set up the DDC bus. */ I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus, diff --git a/src/i830_dvo.c b/src/i830_dvo.c index ed21ecc5..c788e4f4 100644 --- a/src/i830_dvo.c +++ b/src/i830_dvo.c @@ -201,6 +201,7 @@ i830_dvo_init(ScrnInfoPtr pScrn) pI830->output[i].pre_set_mode = i830_dvo_pre_set_mode; pI830->output[i].post_set_mode = i830_dvo_post_set_mode; pI830->output[i].detect = i830_dvo_detect; + pI830->output[i].get_modes = i830_ddc_get_modes; /* Set up the I2C and DDC buses */ ret = I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "DVOI2C_E"); diff --git a/src/i830_lvds.c b/src/i830_lvds.c index e0e471ff..4b899033 100644 --- a/src/i830_lvds.c +++ b/src/i830_lvds.c @@ -235,6 +235,11 @@ i830_lvds_init(ScrnInfoPtr pScrn) pI830->output[pI830->num_outputs].pre_set_mode = i830_lvds_pre_set_mode; pI830->output[pI830->num_outputs].post_set_mode = i830_lvds_post_set_mode; pI830->output[pI830->num_outputs].detect = i830_lvds_detect; + /* This will usually return NULL on laptop panels, which is no good. + * We need to construct a mode from the fixed panel info, and return a copy + * of that when DDC is unavailable. + */ + pI830->output[pI830->num_outputs].get_modes = i830_ddc_get_modes; /* Set up the LVDS DDC channel. Most panels won't support it, but it can * be useful if available. diff --git a/src/i830_modes.c b/src/i830_modes.c index 130b7fe5..1ba1defb 100644 --- a/src/i830_modes.c +++ b/src/i830_modes.c @@ -933,11 +933,22 @@ int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) { I830Ptr pI830 = I830PTR(pScrn); - int pipe; + int pipe, i; DisplayModePtr saved_mode, last; Bool pipes_reconfigured = FALSE; int originalVirtualX, originalVirtualY; + /* Re-probe the list of modes for each output. */ + for (i = 0; i < pI830->num_outputs; i++) { + while (pI830->output[i].probed_modes != NULL) { + xf86DeleteMode(&pI830->output[i].probed_modes, + pI830->output[i].probed_modes); + } + + pI830->output[i].probed_modes = + pI830->output[i].get_modes(pScrn, &pI830->output[i]); + } + for (pipe = 0; pipe < pI830->availablePipes; pipe++) { I830ReprobePipeModeList(pScrn, pipe); } @@ -1099,3 +1110,23 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) return 1; /* XXX */ } + +/** + * Generic get_modes function using DDC, used by many outputs. + */ +DisplayModePtr +i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + xf86MonPtr ddc_mon; + DisplayModePtr ddc_modes; + + ddc_mon = xf86DoEDID_DDC2(pScrn->scrnIndex, output->pDDCBus); + if (ddc_mon == NULL) + return NULL; + + ddc_modes = i830GetDDCModes(pScrn, ddc_mon); + + xfree(ddc_mon); + + return ddc_modes; +} diff --git a/src/i830_randr.c b/src/i830_randr.c index 23ffaf6c..a1c4b12c 100644 --- a/src/i830_randr.c +++ b/src/i830_randr.c @@ -612,7 +612,6 @@ I830RandRSetInfo12 (ScreenPtr pScreen) int p; int clone_types; int crtc_types; - int connection; int pipe_type; int pipe; int subpixel; @@ -631,6 +630,8 @@ I830RandRSetInfo12 (ScreenPtr pScreen) randrp->virtualX, randrp->virtualY); for (i = 0; i < pI830->num_outputs; i++) { + MonPtr mon; + output = &pI830->output[i]; /* * Valid crtcs @@ -705,50 +706,53 @@ I830RandRSetInfo12 (ScreenPtr pScreen) nmode = 0; npreferred = 0; rrmodes = NULL; - if (pipe >= 0) - { - MonPtr mon = pI830->pipeMon[pipe]; - modes = mon->Modes; - for (mode = modes; mode; mode = mode->next) - nmode++; + modes = pI830->output[i].probed_modes; - if (nmode) - { - rrmodes = xalloc (nmode * sizeof (RRModePtr)); - if (!rrmodes) - return FALSE; - nmode = 0; - for (p = 1; p >= 0; p--) - { - for (mode = modes; mode; mode = mode->next) - { - if ((p != 0) == ((mode->type & M_T_PREFERRED) != 0)) - { - modeInfo.nameLength = strlen (mode->name); + if (pI830->output[i].pipe >= 0) + mon = pI830->pipeMon[pipe]; + else + mon = NULL; + + for (mode = modes; mode; mode = mode->next) + nmode++; + + if (nmode) { + rrmodes = xalloc (nmode * sizeof (RRModePtr)); + if (!rrmodes) + return FALSE; + nmode = 0; + + for (p = 1; p >= 0; p--) { + for (mode = modes; mode; mode = mode->next) { + if ((p != 0) == ((mode->type & M_T_PREFERRED) != 0)) { + modeInfo.nameLength = strlen (mode->name); + if (mon != NULL) { modeInfo.mmWidth = mon->widthmm; modeInfo.mmHeight = mon->heightmm; + } else { + modeInfo.mmWidth = 0; + modeInfo.mmHeight = 0; + } - modeInfo.width = mode->HDisplay; - modeInfo.dotClock = mode->Clock * 1000; - modeInfo.hSyncStart = mode->HSyncStart; - modeInfo.hSyncEnd = mode->HSyncEnd; - modeInfo.hTotal = mode->HTotal; - modeInfo.hSkew = mode->HSkew; + modeInfo.width = mode->HDisplay; + modeInfo.dotClock = mode->Clock * 1000; + modeInfo.hSyncStart = mode->HSyncStart; + modeInfo.hSyncEnd = mode->HSyncEnd; + modeInfo.hTotal = mode->HTotal; + modeInfo.hSkew = mode->HSkew; - modeInfo.height = mode->VDisplay; - modeInfo.vSyncStart = mode->VSyncStart; - modeInfo.vSyncEnd = mode->VSyncEnd; - modeInfo.vTotal = mode->VTotal; - modeInfo.modeFlags = mode->Flags; + modeInfo.height = mode->VDisplay; + modeInfo.vSyncStart = mode->VSyncStart; + modeInfo.vSyncEnd = mode->VSyncEnd; + modeInfo.vTotal = mode->VTotal; + modeInfo.modeFlags = mode->Flags; - rrmode = RRModeGet (pScreen, &modeInfo, mode->name); - rrmode->devPrivate = mode; - if (rrmode) - { - rrmodes[nmode++] = rrmode; - npreferred += p; - } + rrmode = RRModeGet (pScreen, &modeInfo, mode->name); + rrmode->devPrivate = mode; + if (rrmode) { + rrmodes[nmode++] = rrmode; + npreferred += p; } } } diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 3932ea65..b6a3d676 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -940,6 +940,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) output->pre_set_mode = i830_sdvo_pre_set_mode; output->post_set_mode = i830_sdvo_post_set_mode; output->detect = i830_sdvo_detect; + output->get_modes = i830_ddc_get_modes; /* While it's the same bus, we just initialize a new copy to avoid trouble * with tracking refcounting ourselves, since the XFree86 DDX bits don't. diff --git a/src/i830_tv.c b/src/i830_tv.c index 3e728822..47c0d03b 100644 --- a/src/i830_tv.c +++ b/src/i830_tv.c @@ -417,6 +417,18 @@ i830_tv_detect(ScrnInfoPtr pScrn, I830OutputPtr output) return OUTPUT_STATUS_UNKNOWN; } +/** + * Stub get_modes function. + * + * This should probably return a set of fixed modes, unless we can figure out + * how to probe modes off of TV connections. + */ +DisplayModePtr +i830_tv_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output) +{ + return NULL; +} + void i830_tv_init(ScrnInfoPtr pScrn) { @@ -438,6 +450,7 @@ i830_tv_init(ScrnInfoPtr pScrn) pI830->output[pI830->num_outputs].pre_set_mode = i830_tv_pre_set_mode; pI830->output[pI830->num_outputs].post_set_mode = i830_tv_post_set_mode; pI830->output[pI830->num_outputs].detect = i830_tv_detect; + pI830->output[pI830->num_outputs].get_modes = i830_tv_get_modes; pI830->num_outputs++; }