st/xorg: attach EDID to outputs
[mesa.git] / src / gallium / state_trackers / xorg / xorg_output.c
index 26f45f8d64592b7ae1deefec210d815904f8633c..b183cdf9dc1df8ca2085f0a3cd32d4f97b8d328c 100644 (file)
@@ -32,6 +32,7 @@
 #include <xf86.h>
 #include <xf86i2c.h>
 #include <xf86Crtc.h>
+#include <xf86DDC.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <X11/extensions/dpms.h>
 #endif
 
-#include "X11/Xatom.h"
-
 #include "xorg_tracker.h"
 
-static char *connector_enum_list[] = {
+struct output_private
+{
+    drmModeConnectorPtr drm_connector;
+    drmModePropertyBlobPtr edid_blob;
+    int fd;
+    int c;
+};
+
+static char *output_enum_list[] = {
     "Unknown",
     "VGA",
-    "DVI-I",
-    "DVI-D",
-    "DVI-A",
+    "DVI",
+    "DVI",
+    "DVI",
     "Composite",
     "SVIDEO",
     "LVDS",
-    "Component",
-    "9-pin DIN",
-    "DisplayPort",
-    "HDMI Type A",
-    "HDMI Type B",
+    "CTV",
+    "DIN",
+    "DP",
+    "HDMI",
+    "HDMI",
 };
 
 static void
-dpms(xf86OutputPtr output, int mode)
-{
-}
-
-static void
-save(xf86OutputPtr output)
-{
-}
-
-static void
-restore(xf86OutputPtr output)
-{
-}
-
-static int
-mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
-{
-    return MODE_OK;
-}
-
-static Bool
-mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
-          DisplayModePtr adjusted_mode)
-{
-    return TRUE;
-}
-
-static void
-prepare(xf86OutputPtr output)
-{
-    dpms(output, DPMSModeOff);
-}
-
-static void
-mode_set(xf86OutputPtr output, DisplayModePtr mode,
-        DisplayModePtr adjusted_mode)
+output_create_resources(xf86OutputPtr output)
 {
+#ifdef RANDR_12_INTERFACE
+#endif /* RANDR_12_INTERFACE */
 }
 
 static void
-commit(xf86OutputPtr output)
+output_dpms(xf86OutputPtr output, int mode)
 {
-    dpms(output, DPMSModeOn);
-
-    if (output->scrn->pScreen != NULL)
-       xf86_reload_cursors(output->scrn->pScreen);
 }
 
 static xf86OutputStatus
-detect(xf86OutputPtr output)
+output_detect(xf86OutputPtr output)
 {
-    drmModeConnectorPtr drm_connector = output->driver_private;
+    modesettingPtr ms = modesettingPTR(output->scrn);
+    struct output_private *priv = output->driver_private;
+    drmModeConnectorPtr drm_connector;
+    xf86OutputStatus status;
+
+    drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
+    if (drm_connector) {
+       drmModeFreeConnector(priv->drm_connector);
+       priv->drm_connector = drm_connector;
+    } else {
+       drm_connector = priv->drm_connector;
+    }
 
     switch (drm_connector->connection) {
     case DRM_MODE_CONNECTED:
-       return XF86OutputStatusConnected;
+       status = XF86OutputStatusConnected;
+       break;
     case DRM_MODE_DISCONNECTED:
-       return XF86OutputStatusDisconnected;
+       status = XF86OutputStatusDisconnected;
+       break;
     default:
-       return XF86OutputStatusUnknown;
+       status = XF86OutputStatusUnknown;
     }
+
+    return status;
 }
 
 static DisplayModePtr
-get_modes(xf86OutputPtr output)
+output_get_modes(xf86OutputPtr output)
 {
-    drmModeConnectorPtr drm_connector = output->driver_private;
+    struct output_private *priv = output->driver_private;
+    drmModeConnectorPtr drm_connector = priv->drm_connector;
     drmModeModeInfoPtr drm_mode = NULL;
+    drmModePropertyPtr props = NULL;
+    xf86MonPtr ddc_mon = NULL;
     DisplayModePtr modes = NULL, mode = NULL;
     int i;
 
+       for (i = 0; i < drm_connector->count_props; i++) {
+               props = drmModeGetProperty(priv->fd, drm_connector->props[i]);
+               if (!props)
+                       continue;
+
+               if (!(props->flags & DRM_MODE_PROP_BLOB))
+                       goto out_free;
+
+               if (!strcmp(props->name, "EDID")) {
+                       if (priv->edid_blob)
+                               drmModeFreePropertyBlob(priv->edid_blob);
+                       priv->edid_blob = drmModeGetPropertyBlob(priv->fd,
+                                                         drm_connector->prop_values[i]);
+               }
+
+               out_free:
+               drmModeFreeProperty(props);
+       }
+
+       if (priv->edid_blob) {
+               ddc_mon = xf86InterpretEDID(output->scrn->scrnIndex,
+                                                                       priv->edid_blob->data);
+
+               if (ddc_mon && priv->edid_blob->length > 128)
+                       ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
+       }
+       xf86OutputSetEDID(output, ddc_mon);
+
     for (i = 0; i < drm_connector->count_modes; i++) {
        drm_mode = &drm_connector->modes[i];
        if (drm_mode) {
-           mode = xcalloc(1, sizeof(DisplayModeRec));
+           mode = calloc(1, sizeof(DisplayModeRec));
            if (!mode)
                continue;
-           mode->type = 0;
            mode->Clock = drm_mode->clock;
            mode->HDisplay = drm_mode->hdisplay;
            mode->HSyncStart = drm_mode->hsync_start;
@@ -162,6 +177,11 @@ get_modes(xf86OutputPtr output)
            mode->VScan = drm_mode->vscan;
            mode->VRefresh = xf86ModeVRefresh(mode);
            mode->Private = (void *)drm_mode;
+           mode->type = 0;
+           if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
+               mode->type |= M_T_PREFERRED;
+           if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
+               mode->type |= M_T_DRIVER;
            xf86SetModeDefaultName(mode);
            modes = xf86ModesAdd(modes, mode);
            xf86PrintModeline(0, mode);
@@ -171,22 +191,24 @@ get_modes(xf86OutputPtr output)
     return modes;
 }
 
-static void
-destroy(xf86OutputPtr output)
+static int
+output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 {
-    drmModeFreeConnector(output->driver_private);
-}
+    modesettingPtr ms = modesettingPTR(output->scrn);
+    CustomizerPtr cust = ms->cust;
 
-static void
-create_resources(xf86OutputPtr output)
-{
-#ifdef RANDR_12_INTERFACE
-#endif /* RANDR_12_INTERFACE */
+    if (cust && cust->winsys_check_fb_size &&
+       !cust->winsys_check_fb_size(cust, pMode->HDisplay *
+                                   output->scrn->bitsPerPixel / 8,
+                                   pMode->VDisplay))
+       return MODE_BAD;
+
+    return MODE_OK;
 }
 
 #ifdef RANDR_12_INTERFACE
 static Bool
-set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
+output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
 {
     return TRUE;
 }
@@ -194,53 +216,49 @@ set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
 
 #ifdef RANDR_13_INTERFACE
 static Bool
-get_property(xf86OutputPtr output, Atom property)
+output_get_property(xf86OutputPtr output, Atom property)
 {
     return TRUE;
 }
 #endif /* RANDR_13_INTERFACE */
 
-#ifdef RANDR_GET_CRTC_INTERFACE
-static xf86CrtcPtr
-get_crtc(xf86OutputPtr output)
+static void
+output_destroy(xf86OutputPtr output)
 {
-    return NULL;
+    struct output_private *priv = output->driver_private;
+    if (priv->edid_blob)
+               drmModeFreePropertyBlob(priv->edid_blob);
+    drmModeFreeConnector(priv->drm_connector);
+    free(priv);
+    output->driver_private = NULL;
 }
-#endif
 
 static const xf86OutputFuncsRec output_funcs = {
-    .create_resources = create_resources,
-    .dpms = dpms,
-    .save = save,
-    .restore = restore,
-    .mode_valid = mode_valid,
-    .mode_fixup = mode_fixup,
-    .prepare = prepare,
-    .mode_set = mode_set,
-    .commit = commit,
-    .detect = detect,
-    .get_modes = get_modes,
+    .create_resources = output_create_resources,
 #ifdef RANDR_12_INTERFACE
-    .set_property = set_property,
+    .set_property = output_set_property,
 #endif
 #ifdef RANDR_13_INTERFACE
-    .get_property = get_property,
-#endif
-    .destroy = destroy,
-#ifdef RANDR_GET_CRTC_INTERFACE
-    .get_crtc = get_crtc,
+    .get_property = output_get_property,
 #endif
+    .dpms = output_dpms,
+    .detect = output_detect,
+
+    .get_modes = output_get_modes,
+    .mode_valid = output_mode_valid,
+    .destroy = output_destroy,
 };
 
 void
-output_init(ScrnInfoPtr pScrn)
+xorg_output_init(ScrnInfoPtr pScrn)
 {
     modesettingPtr ms = modesettingPTR(pScrn);
     xf86OutputPtr output;
     drmModeResPtr res;
     drmModeConnectorPtr drm_connector = NULL;
     drmModeEncoderPtr drm_encoder = NULL;
-    char *name;
+    struct output_private *priv;
+    char name[32];
     int c, v, p;
 
     res = drmModeGetResources(ms->fd);
@@ -273,11 +291,21 @@ output_init(ScrnInfoPtr pScrn)
        (void)v;
 #endif
 
-       name = connector_enum_list[drm_connector->connector_type];
+       snprintf(name, 32, "%s%d",
+                output_enum_list[drm_connector->connector_type],
+                drm_connector->connector_type_id);
+
+
+       priv = calloc(sizeof(*priv), 1);
+       if (!priv) {
+           continue;
+       }
 
        output = xf86OutputCreate(pScrn, &output_funcs, name);
-       if (!output)
+       if (!output) {
+           free(priv);
            continue;
+       }
 
        drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
        if (drm_encoder) {
@@ -287,7 +315,10 @@ output_init(ScrnInfoPtr pScrn)
            output->possible_crtcs = 0;
            output->possible_clones = 0;
        }
-       output->driver_private = drm_connector;
+       priv->c = c;
+       priv->drm_connector = drm_connector;
+       priv->fd = ms->fd;
+       output->driver_private = priv;
        output->subpixel_order = SubPixelHorizontalRGB;
        output->interlaceAllowed = FALSE;
        output->doubleScanAllowed = FALSE;
@@ -297,4 +328,11 @@ output_init(ScrnInfoPtr pScrn)
     drmModeFreeResources(res);
 }
 
+unsigned
+xorg_output_get_id(xf86OutputPtr output)
+{
+    struct output_private *priv = output->driver_private;
+    return priv->drm_connector->connector_id;
+}
+
 /* vim: set sw=4 ts=8 sts=4: */