Home | History | Annotate | Download | only in xorg
      1 /*
      2  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  *
     26  * Author: Alan Hourihane <alanh (at) tungstengraphics.com>
     27  * Author: Jakob Bornecrantz <wallbraker (at) gmail.com>
     28  *
     29  */
     30 
     31 #include "xorg-server.h"
     32 #include <xf86.h>
     33 #include <xf86i2c.h>
     34 #include <xf86Crtc.h>
     35 #include <xf86DDC.h>
     36 #include <errno.h>
     37 #include <fcntl.h>
     38 #include <unistd.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <stdint.h>
     42 #include <string.h>
     43 #include <sys/stat.h>
     44 #include <sys/types.h>
     45 
     46 #ifdef HAVE_XEXTPROTO_71
     47 #include <X11/extensions/dpmsconst.h>
     48 #else
     49 #define DPMS_SERVER
     50 #include <X11/extensions/dpms.h>
     51 #endif
     52 
     53 #include "xorg_tracker.h"
     54 
     55 struct output_private
     56 {
     57     drmModeConnectorPtr drm_connector;
     58     drmModePropertyBlobPtr edid_blob;
     59     int fd;
     60     int c;
     61 };
     62 
     63 static char *output_enum_list[] = {
     64     "Unknown",
     65     "VGA",
     66     "DVI",
     67     "DVI",
     68     "DVI",
     69     "Composite",
     70     "SVIDEO",
     71     "LVDS",
     72     "CTV",
     73     "DIN",
     74     "DP",
     75     "HDMI",
     76     "HDMI",
     77 };
     78 
     79 static void
     80 output_create_resources(xf86OutputPtr output)
     81 {
     82 #ifdef RANDR_12_INTERFACE
     83 #endif /* RANDR_12_INTERFACE */
     84 }
     85 
     86 static void
     87 output_dpms(xf86OutputPtr output, int mode)
     88 {
     89 }
     90 
     91 static xf86OutputStatus
     92 output_detect(xf86OutputPtr output)
     93 {
     94     modesettingPtr ms = modesettingPTR(output->scrn);
     95     struct output_private *priv = output->driver_private;
     96     drmModeConnectorPtr drm_connector;
     97     xf86OutputStatus status;
     98 
     99     drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
    100     if (drm_connector) {
    101 	drmModeFreeConnector(priv->drm_connector);
    102 	priv->drm_connector = drm_connector;
    103     } else {
    104 	drm_connector = priv->drm_connector;
    105     }
    106 
    107     switch (drm_connector->connection) {
    108     case DRM_MODE_CONNECTED:
    109 	status = XF86OutputStatusConnected;
    110 	break;
    111     case DRM_MODE_DISCONNECTED:
    112 	status = XF86OutputStatusDisconnected;
    113 	break;
    114     default:
    115 	status = XF86OutputStatusUnknown;
    116     }
    117 
    118     return status;
    119 }
    120 
    121 static DisplayModePtr
    122 output_get_modes(xf86OutputPtr output)
    123 {
    124     struct output_private *priv = output->driver_private;
    125     drmModeConnectorPtr drm_connector = priv->drm_connector;
    126     drmModeModeInfoPtr drm_mode = NULL;
    127     drmModePropertyPtr props = NULL;
    128     xf86MonPtr ddc_mon = NULL;
    129     DisplayModePtr modes = NULL, mode = NULL;
    130     int i;
    131 
    132 	for (i = 0; i < drm_connector->count_props; i++) {
    133 		props = drmModeGetProperty(priv->fd, drm_connector->props[i]);
    134 		if (!props)
    135 			continue;
    136 
    137 		if (!(props->flags & DRM_MODE_PROP_BLOB))
    138 			goto out_free;
    139 
    140 		if (!strcmp(props->name, "EDID")) {
    141 			if (priv->edid_blob)
    142 				drmModeFreePropertyBlob(priv->edid_blob);
    143 			priv->edid_blob = drmModeGetPropertyBlob(priv->fd,
    144 							  drm_connector->prop_values[i]);
    145 		}
    146 
    147 		out_free:
    148 		drmModeFreeProperty(props);
    149 	}
    150 
    151 	if (priv->edid_blob) {
    152 		ddc_mon = xf86InterpretEDID(output->scrn->scrnIndex,
    153 									priv->edid_blob->data);
    154 
    155 		if (ddc_mon && priv->edid_blob->length > 128)
    156 			ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
    157 	}
    158 	xf86OutputSetEDID(output, ddc_mon);
    159 
    160     for (i = 0; i < drm_connector->count_modes; i++) {
    161 	drm_mode = &drm_connector->modes[i];
    162 	if (drm_mode) {
    163 	    mode = calloc(1, sizeof(DisplayModeRec));
    164 	    if (!mode)
    165 		continue;
    166 	    mode->Clock = drm_mode->clock;
    167 	    mode->HDisplay = drm_mode->hdisplay;
    168 	    mode->HSyncStart = drm_mode->hsync_start;
    169 	    mode->HSyncEnd = drm_mode->hsync_end;
    170 	    mode->HTotal = drm_mode->htotal;
    171 	    mode->VDisplay = drm_mode->vdisplay;
    172 	    mode->VSyncStart = drm_mode->vsync_start;
    173 	    mode->VSyncEnd = drm_mode->vsync_end;
    174 	    mode->VTotal = drm_mode->vtotal;
    175 	    mode->Flags = drm_mode->flags;
    176 	    mode->HSkew = drm_mode->hskew;
    177 	    mode->VScan = drm_mode->vscan;
    178 	    mode->VRefresh = xf86ModeVRefresh(mode);
    179 	    mode->Private = (void *)drm_mode;
    180 	    mode->type = 0;
    181 	    if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
    182 		mode->type |= M_T_PREFERRED;
    183 	    if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
    184 		mode->type |= M_T_DRIVER;
    185 	    xf86SetModeDefaultName(mode);
    186 	    modes = xf86ModesAdd(modes, mode);
    187 	    xf86PrintModeline(0, mode);
    188 	}
    189     }
    190 
    191     return modes;
    192 }
    193 
    194 static int
    195 output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
    196 {
    197     modesettingPtr ms = modesettingPTR(output->scrn);
    198     CustomizerPtr cust = ms->cust;
    199 
    200     if (cust && cust->winsys_check_fb_size &&
    201 	!cust->winsys_check_fb_size(cust, pMode->HDisplay *
    202 				    output->scrn->bitsPerPixel / 8,
    203 				    pMode->VDisplay))
    204 	return MODE_BAD;
    205 
    206     return MODE_OK;
    207 }
    208 
    209 #ifdef RANDR_12_INTERFACE
    210 static Bool
    211 output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
    212 {
    213     return TRUE;
    214 }
    215 #endif /* RANDR_12_INTERFACE */
    216 
    217 #ifdef RANDR_13_INTERFACE
    218 static Bool
    219 output_get_property(xf86OutputPtr output, Atom property)
    220 {
    221     return TRUE;
    222 }
    223 #endif /* RANDR_13_INTERFACE */
    224 
    225 static void
    226 output_destroy(xf86OutputPtr output)
    227 {
    228     struct output_private *priv = output->driver_private;
    229     if (priv->edid_blob)
    230 		drmModeFreePropertyBlob(priv->edid_blob);
    231     drmModeFreeConnector(priv->drm_connector);
    232     free(priv);
    233     output->driver_private = NULL;
    234 }
    235 
    236 static const xf86OutputFuncsRec output_funcs = {
    237     .create_resources = output_create_resources,
    238 #ifdef RANDR_12_INTERFACE
    239     .set_property = output_set_property,
    240 #endif
    241 #ifdef RANDR_13_INTERFACE
    242     .get_property = output_get_property,
    243 #endif
    244     .dpms = output_dpms,
    245     .detect = output_detect,
    246 
    247     .get_modes = output_get_modes,
    248     .mode_valid = output_mode_valid,
    249     .destroy = output_destroy,
    250 };
    251 
    252 void
    253 xorg_output_init(ScrnInfoPtr pScrn)
    254 {
    255     modesettingPtr ms = modesettingPTR(pScrn);
    256     xf86OutputPtr output;
    257     drmModeResPtr res;
    258     drmModeConnectorPtr drm_connector = NULL;
    259     drmModeEncoderPtr drm_encoder = NULL;
    260     struct output_private *priv;
    261     char name[32];
    262     int c, v, p;
    263 
    264     res = drmModeGetResources(ms->fd);
    265     if (res == 0) {
    266 	DRV_ERROR("Failed drmModeGetResources\n");
    267 	return;
    268     }
    269 
    270     for (c = 0; c < res->count_connectors; c++) {
    271 	drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]);
    272 	if (!drm_connector)
    273 	    goto out;
    274 
    275 #if 0
    276 	for (p = 0; p < drm_connector->count_props; p++) {
    277 	    drmModePropertyPtr prop;
    278 
    279 	    prop = drmModeGetProperty(ms->fd, drm_connector->props[p]);
    280 
    281 	    name = NULL;
    282 	    if (prop) {
    283 		ErrorF("VALUES %d\n", prop->count_values);
    284 
    285 		for (v = 0; v < prop->count_values; v++)
    286 		    ErrorF("%s %lld\n", prop->name, prop->values[v]);
    287 	    }
    288 	}
    289 #else
    290 	(void)p;
    291 	(void)v;
    292 #endif
    293 
    294 	snprintf(name, 32, "%s%d",
    295 		 output_enum_list[drm_connector->connector_type],
    296 		 drm_connector->connector_type_id);
    297 
    298 
    299 	priv = calloc(sizeof(*priv), 1);
    300 	if (!priv) {
    301 	    continue;
    302 	}
    303 
    304 	output = xf86OutputCreate(pScrn, &output_funcs, name);
    305 	if (!output) {
    306 	    free(priv);
    307 	    continue;
    308 	}
    309 
    310 	drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
    311 	if (drm_encoder) {
    312 	    output->possible_crtcs = drm_encoder->possible_crtcs;
    313 	    output->possible_clones = drm_encoder->possible_clones;
    314 	} else {
    315 	    output->possible_crtcs = 0;
    316 	    output->possible_clones = 0;
    317 	}
    318 	priv->c = c;
    319 	priv->drm_connector = drm_connector;
    320 	priv->fd = ms->fd;
    321 	output->driver_private = priv;
    322 	output->subpixel_order = SubPixelHorizontalRGB;
    323 	output->interlaceAllowed = FALSE;
    324 	output->doubleScanAllowed = FALSE;
    325     }
    326 
    327   out:
    328     drmModeFreeResources(res);
    329 }
    330 
    331 unsigned
    332 xorg_output_get_id(xf86OutputPtr output)
    333 {
    334     struct output_private *priv = output->driver_private;
    335     return priv->drm_connector->connector_id;
    336 }
    337 
    338 /* vim: set sw=4 ts=8 sts=4: */
    339