Give each output a get_modes function and expose those modes through RandR.

The get_modes should return the probed modes only.  The driver should then
append to the list (for example, compatible modes listed in other outputs,
or standard VESA modes) to create the list to expose through RandR.  That
isn't done yet.
This commit is contained in:
Eric Anholt 2006-10-31 17:10:08 -08:00
parent cc3728be24
commit 7195dfabd5
8 changed files with 110 additions and 39 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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");

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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.

View File

@ -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++;
}