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@tungstengraphics.com>
27  * Author: Jakob Bornecrantz <wallbraker@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
output_create_resources(xf86OutputPtr output)80 output_create_resources(xf86OutputPtr output)
81 {
82 #ifdef RANDR_12_INTERFACE
83 #endif /* RANDR_12_INTERFACE */
84 }
85 
86 static void
output_dpms(xf86OutputPtr output,int mode)87 output_dpms(xf86OutputPtr output, int mode)
88 {
89 }
90 
91 static xf86OutputStatus
output_detect(xf86OutputPtr output)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
output_get_modes(xf86OutputPtr output)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
output_mode_valid(xf86OutputPtr output,DisplayModePtr pMode)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
output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)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
output_get_property(xf86OutputPtr output,Atom property)219 output_get_property(xf86OutputPtr output, Atom property)
220 {
221     return TRUE;
222 }
223 #endif /* RANDR_13_INTERFACE */
224 
225 static void
output_destroy(xf86OutputPtr output)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
xorg_output_init(ScrnInfoPtr pScrn)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
xorg_output_get_id(xf86OutputPtr output)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