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