From 566eea7757b3a0edf85e629e68f3b8cd0efac7b8 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Feb 2009 14:24:24 +0800 Subject: [PATCH] SDVO: handle multifunction encoder (try 2) For SDVO encoder that advertise multiple functions, we have to get attached display to determine current output, and update output's name according with current type. --- src/i830_sdvo.c | 225 +++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 160 insertions(+), 65 deletions(-) diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 4b98a9b..28040f5 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -66,6 +66,14 @@ struct i830_sdvo_priv { */ struct i830_sdvo_caps caps; + /** + * For multiple function SDVO device, this is for current attached outputs. + */ + uint16_t attached_output; + + /* Current output type name */ + char *name; + /** Pixel clock limitations reported by the SDVO device, in kHz */ int pixel_clock_min, pixel_clock_max; @@ -1516,6 +1524,135 @@ i830_sdvo_check_hdmi_encode (xf86OutputPtr output) return FALSE; } +static void i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv); + +static Bool +i830_sdvo_output_setup (xf86OutputPtr output, uint16_t flag) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + char *name_prefix; + char *name_suffix; + + if (dev_priv->output_device == SDVOB) + name_suffix = "-1"; + else + name_suffix = "-2"; + + if (flag & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) + { + if (flag & SDVO_OUTPUT_TMDS0) + dev_priv->controlled_output = SDVO_OUTPUT_TMDS0; + else + dev_priv->controlled_output = SDVO_OUTPUT_TMDS1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="TMDS"; + + if (i830_sdvo_check_hdmi_encode (output)) + name_prefix = "HDMI"; + } + else if (flag & SDVO_OUTPUT_SVID0) + { + dev_priv->controlled_output = SDVO_OUTPUT_SVID0; + output->subpixel_order = SubPixelHorizontalRGB; /* XXX */ + name_prefix="TV"; + dev_priv->is_tv = TRUE; + intel_output->needs_tv_clock = TRUE; + } + else if (flag & SDVO_OUTPUT_RGB0) + { + dev_priv->controlled_output = SDVO_OUTPUT_RGB0; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="VGA"; + } + else if (flag & SDVO_OUTPUT_RGB1) + { + dev_priv->controlled_output = SDVO_OUTPUT_RGB1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="VGA"; + } else if (flag & SDVO_OUTPUT_LVDS0) { + dev_priv->controlled_output = SDVO_OUTPUT_LVDS0; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="LVDS"; + } else if (flag & SDVO_OUTPUT_LVDS1) { + dev_priv->controlled_output = SDVO_OUTPUT_LVDS1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="LVDS"; + } else { + unsigned char bytes[2]; + + dev_priv->controlled_output = 0; + memcpy (bytes, &flag, 2); + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING, + "%s: Unknown SDVO output type (0x%02x%02x)\n", + SDVO_NAME(dev_priv), + bytes[0], bytes[1]); + name_prefix="Unknown"; + } + + /* if exist origin name it will be freed in xf86OutputRename() */ + dev_priv->name = xalloc(strlen(name_prefix) + strlen(name_suffix) + 1); + strcpy (dev_priv->name, name_prefix); + strcat (dev_priv->name, name_suffix); + + if (!xf86OutputRename (output, dev_priv->name)) + { + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING, + "%s: Failed to rename output to %s\n", + SDVO_NAME(dev_priv), dev_priv->name); + xf86OutputDestroy (output); + return FALSE; + } + + /* update randr_output's name */ + if (output->randr_output) { + int nameLength = strlen(dev_priv->name); + RROutputPtr randr_output = output->randr_output; + char *name = xalloc(nameLength + 1); + + if (name) { + if (randr_output->name != (char *) (randr_output + 1)) + xfree(randr_output->name); + randr_output->name = name; + randr_output->nameLength = nameLength; + memcpy(randr_output->name, dev_priv->name, nameLength); + randr_output->name[nameLength] = '\0'; + } else + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING, + "%s: Failed to update RandR output name to %s\n", + SDVO_NAME(dev_priv), dev_priv->name); + } + + i830_sdvo_select_ddc_bus(dev_priv); + + return TRUE; +} + +static Bool +i830_sdvo_multifunc_encoder(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + int caps = 0; + + if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | + SDVO_OUTPUT_TMDS1)) + caps++; + if (dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB0 | + SDVO_OUTPUT_RGB1)) + caps++; + if (dev_priv->caps.output_flags & (SDVO_OUTPUT_CVBS0 | + SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0 | + SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_CVBS1 | + SDVO_OUTPUT_SVID1 | SDVO_OUTPUT_YPRPB1 | + SDVO_OUTPUT_SCART1)) + caps++; + if (dev_priv->caps.output_flags & (SDVO_OUTPUT_LVDS0 | + SDVO_OUTPUT_LVDS1)) + caps++; + return (caps > 1); +} + /** * Asks the SDVO device if any displays are currently connected. * @@ -1542,6 +1679,14 @@ i830_sdvo_detect(xf86OutputPtr output) if (response == 0) return XF86OutputStatusDisconnected; + if (i830_sdvo_multifunc_encoder(output)) { + if (dev_priv->attached_output != response) { + if (!i830_sdvo_output_setup(output, response)) + return XF86OutputStatusUnknown; + dev_priv->attached_output = response; + } + } + if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { xf86MonPtr edid_mon; @@ -1735,10 +1880,18 @@ i830_sdvo_destroy (xf86OutputPtr output) if (intel_output) { struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; - + xf86DestroyI2CBusRec (intel_output->pDDCBus, FALSE, FALSE); xf86DestroyI2CDevRec (&dev_priv->d, FALSE); xf86DestroyI2CBusRec (dev_priv->d.pI2CBus, TRUE, TRUE); + + if (output->randr_output) { + RROutputPtr randr_output = output->randr_output; + if (randr_output->name && + randr_output->name != (char *) (randr_output + 1)) + xfree(randr_output->name); + } + xfree (intel_output); } } @@ -1838,9 +1991,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) int i; unsigned char ch[0x40]; I2CBusPtr i2cbus = NULL, ddcbus; - char name[60]; - char *name_prefix; - char *name_suffix; output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL); if (!output) @@ -1880,11 +2030,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) if (output_device == SDVOB) { dev_priv->d.DevName = "SDVO Controller B"; dev_priv->d.SlaveAddr = 0x70; - name_suffix="-1"; } else { dev_priv->d.DevName = "SDVO Controller C"; dev_priv->d.SlaveAddr = 0x72; - name_suffix="-2"; } dev_priv->d.pI2CBus = i2cbus; dev_priv->d.DriverPrivate.ptr = output; @@ -1945,70 +2093,17 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) intel_output->pDDCBus = ddcbus; intel_output->dev_priv = dev_priv; - i830_sdvo_get_capabilities(output, &dev_priv->caps); - - if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) - { - if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) - dev_priv->controlled_output = SDVO_OUTPUT_TMDS0; - else - dev_priv->controlled_output = SDVO_OUTPUT_TMDS1; - output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="TMDS"; - - if (i830_sdvo_check_hdmi_encode (output)) - name_prefix = "HDMI"; - } - else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0) - { - dev_priv->controlled_output = SDVO_OUTPUT_SVID0; - output->subpixel_order = SubPixelHorizontalRGB; /* XXX */ - name_prefix="TV"; - dev_priv->is_tv = TRUE; - intel_output->needs_tv_clock = TRUE; - } - else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0) - { - dev_priv->controlled_output = SDVO_OUTPUT_RGB0; - output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="VGA"; - } - else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB1) - { - dev_priv->controlled_output = SDVO_OUTPUT_RGB1; - output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="VGA"; - } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) { - dev_priv->controlled_output = SDVO_OUTPUT_LVDS0; - output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="LVDS"; - } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) { - dev_priv->controlled_output = SDVO_OUTPUT_LVDS1; - output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="LVDS"; - } - else - { - unsigned char bytes[2]; - - dev_priv->controlled_output = 0; - memcpy (bytes, &dev_priv->caps.output_flags, 2); - xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING, - "%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(dev_priv), - bytes[0], bytes[1]); - name_prefix="Unknown"; - } - - strcpy (name, name_prefix); - strcat (name, name_suffix); - if (!xf86OutputRename (output, name)) + if (!i830_sdvo_get_capabilities(output, &dev_priv->caps)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to get %s capabilities\n", + SDVO_NAME(dev_priv)); xf86OutputDestroy (output); return FALSE; } - i830_sdvo_select_ddc_bus(dev_priv); + if (!i830_sdvo_output_setup (output, dev_priv->caps.output_flags)) + return FALSE; /* Set the input timing to the screen. Assume always input 0. */ i830_sdvo_set_target_input(output, TRUE, FALSE); -- 1.5.6.5