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#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "xorg-server.h"
35#include <xf86drm.h>
36#include <xf86str.h>
37#include <randrstr.h>
38#include <xf86Crtc.h>
39#include <X11/Xatom.h>
40#include <dix.h>
41
42#ifdef HAVE_XEXTPROTO_71
43#include <X11/extensions/dpmsconst.h>
44#else
45#define DPMS_SERVER
46#include <X11/extensions/dpms.h>
47#endif
48
49#include "vmwgfx_driver.h"
50
51/**
52 * struct output_prop - Structure representing an output property.
53 *
54 * @mode_prop: Pointer to the corresponding drmModeProperty or
55 * NULL if the property doesn't have a DRM counterpart.
56 * @value: The value of the property.
57 * @num_atoms: Number of atoms in the @atoms array.
58 * @atoms: Atoms used by this poperty.
59 * @index: Index into the drm connector prop_values array.
60 */
61struct output_prop {
62    drmModePropertyPtr mode_prop;
63    uint64_t value;
64    int num_atoms;
65    Atom *atoms;
66    int index;
67};
68
69struct output_private
70{
71    drmModeConnectorPtr drm_connector;
72    int num_props;
73    struct output_prop *props;
74    int c;
75    int suggested_x;
76    int suggested_y;
77    int implicit_placement;
78    xf86CrtcPtr saved_crtc;
79    Bool saved_crtc_enabled;
80};
81
82static const char *output_enum_list[] = {
83    "Unknown",
84    "VGA",
85    "DVI",
86    "DVI",
87    "DVI",
88    "Composite",
89    "SVIDEO",
90    "LVDS",
91    "CTV",
92    "DIN",
93    "DP",
94    "HDMI",
95    "HDMI",
96    "TV",
97    "EDP",
98    "Virtual",
99};
100
101/**
102 * vmwgfx_output_has_origin - Whether we've detected layout info on the DRM
103 * connector.
104 *
105 * @output: The output to consider.
106 *
107 * Returns: TRUE if the corresponding DRM connector has layout info.
108 * FALSE otherwise.
109 */
110Bool
111vmwgfx_output_has_origin(xf86OutputPtr output)
112{
113    struct output_private *vmwgfx_output = output->driver_private;
114
115    return vmwgfx_output->suggested_x != -1 &&
116	vmwgfx_output->suggested_y != -1;
117}
118
119/**
120 * vmwgfx_output_origin - Get the origin for an output in the GUI layout.
121 *
122 * @output: The output to consider.
123 * @x: Outputs the x coordinate of the origin.
124 * @y: Outputs the y coordinate of the origin.
125 */
126void
127vmwgfx_output_origin(xf86OutputPtr output, int *x, int *y)
128{
129    struct output_private *vmwgfx_output = output->driver_private;
130
131    *x = vmwgfx_output->props[vmwgfx_output->suggested_x].value;
132    *y = vmwgfx_output->props[vmwgfx_output->suggested_y].value;
133}
134
135/**
136 * vmwgfx_output_is_implicit - Whether an output uses implicit placement
137 *
138 * output: The output to consider.
139 *
140 * Returns: TRUE if the output uses implicit placement. False otherwise.
141 */
142static Bool
143vmwgfx_output_is_implicit(xf86OutputPtr output)
144{
145    struct output_private *vmwgfx_output = output->driver_private;
146
147    if (vmwgfx_output->implicit_placement == -1)
148	return TRUE;
149
150    return !!vmwgfx_output->props[vmwgfx_output->implicit_placement].value;
151}
152
153/**
154 * output_property_ignore - Function to determine whether to ignore or
155 * to re-export a drm property.
156 *
157 * @prop: Pointer to the drmModeProperty to consider
158 *
159 * RETURNS: TRUE if the property should be re-exported. FALSE otherwise.
160 */
161static Bool
162output_property_ignore(drmModePropertyPtr prop)
163{
164    if (!prop)
165	return TRUE;
166    /* ignore blob prop */
167    if (prop->flags & DRM_MODE_PROP_BLOB)
168	return TRUE;
169    /* ignore standard property */
170    if (!strcmp(prop->name, "EDID") ||
171	!strcmp(prop->name, "DPMS") ||
172	!strcmp(prop->name, "dirty"))
173	return TRUE;
174
175    return FALSE;
176}
177
178static void
179output_create_resources(xf86OutputPtr output)
180{
181    modesettingPtr ms = modesettingPTR(output->scrn);
182    struct output_private *vmwgfx_output = output->driver_private;
183    drmModeConnectorPtr drm_connector = vmwgfx_output->drm_connector;
184    drmModePropertyPtr drmmode_prop;
185    int i, j, err;
186
187    vmwgfx_output->props = calloc(drm_connector->count_props,
188				  sizeof(struct output_prop));
189    if (!vmwgfx_output->props)
190	return;
191
192    vmwgfx_output->num_props = 0;
193    for (i = 0, j = 0; i < drm_connector->count_props; i++) {
194	drmmode_prop = drmModeGetProperty(ms->fd, drm_connector->props[i]);
195	if (output_property_ignore(drmmode_prop)) {
196	    drmModeFreeProperty(drmmode_prop);
197	    continue;
198	}
199	vmwgfx_output->props[j].index = i;
200	vmwgfx_output->props[j].mode_prop = drmmode_prop;
201	vmwgfx_output->props[j].value = drm_connector->prop_values[i];
202	if (!strcmp(drmmode_prop->name,"suggested X"))
203	    vmwgfx_output->suggested_x = j;
204	if (!strcmp(drmmode_prop->name,"suggested Y"))
205	    vmwgfx_output->suggested_y = j;
206	if (!strcmp(drmmode_prop->name,"implicit_placement"))
207	    vmwgfx_output->implicit_placement = j;
208	vmwgfx_output->num_props++;
209	j++;
210    }
211
212    for (i = 0; i < vmwgfx_output->num_props; i++) {
213	struct output_prop *p = &vmwgfx_output->props[i];
214	drmmode_prop = p->mode_prop;
215
216	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
217	    INT32 qrange[2];
218	    INT32 value = p->value;
219
220	    p->num_atoms = 1;
221	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
222	    if (!p->atoms)
223		continue;
224	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
225	    qrange[0] = drmmode_prop->values[0];
226	    qrange[1] = drmmode_prop->values[1];
227	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
228		    FALSE, TRUE,
229		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
230		    2, qrange);
231	    if (err != 0) {
232		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
233			"RRConfigureOutputProperty error, %d\n", err);
234	    }
235	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
236		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
237	    if (err != 0) {
238		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
239			"RRChangeOutputProperty error, %d\n", err);
240	    }
241	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
242	    p->num_atoms = drmmode_prop->count_enums + 1;
243	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
244	    if (!p->atoms)
245		continue;
246	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
247	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
248		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
249		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
250	    }
251	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
252		    FALSE, FALSE,
253		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
254		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
255	    if (err != 0) {
256		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
257			"RRConfigureOutputProperty error, %d\n", err);
258	    }
259	    for (j = 0; j < drmmode_prop->count_enums; j++)
260		if (drmmode_prop->enums[j].value == p->value)
261		    break;
262	    /* there's always a matching value */
263	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
264		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
265	    if (err != 0) {
266		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
267			"RRChangeOutputProperty error, %d\n", err);
268	    }
269	}
270    }
271}
272
273static void
274output_dpms(xf86OutputPtr output, int mode)
275{
276}
277
278static xf86OutputStatus
279output_detect(xf86OutputPtr output)
280{
281    modesettingPtr ms = modesettingPTR(output->scrn);
282    struct output_private *priv = output->driver_private;
283    drmModeConnectorPtr drm_connector;
284    xf86OutputStatus status;
285
286    drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
287    if (drm_connector) {
288	drmModeFreeConnector(priv->drm_connector);
289	priv->drm_connector = drm_connector;
290    } else {
291	drm_connector = priv->drm_connector;
292    }
293
294    switch (drm_connector->connection) {
295    case DRM_MODE_CONNECTED:
296	status = XF86OutputStatusConnected;
297	break;
298    case DRM_MODE_DISCONNECTED:
299	status = XF86OutputStatusDisconnected;
300	break;
301    default:
302	status = XF86OutputStatusUnknown;
303    }
304
305    return status;
306}
307
308static DisplayModePtr
309output_get_modes(xf86OutputPtr output)
310{
311    struct output_private *priv = output->driver_private;
312    drmModeConnectorPtr drm_connector = priv->drm_connector;
313    drmModeModeInfoPtr drm_mode = NULL;
314    DisplayModePtr modes = NULL, mode = NULL;
315    int i;
316
317    for (i = 0; i < drm_connector->count_modes; i++) {
318	drm_mode = &drm_connector->modes[i];
319	if (drm_mode) {
320	    mode = calloc(1, sizeof(DisplayModeRec));
321	    if (!mode)
322		continue;
323	    mode->Clock = drm_mode->clock;
324	    mode->HDisplay = drm_mode->hdisplay;
325	    mode->HSyncStart = drm_mode->hsync_start;
326	    mode->HSyncEnd = drm_mode->hsync_end;
327	    mode->HTotal = drm_mode->htotal;
328	    mode->VDisplay = drm_mode->vdisplay;
329	    mode->VSyncStart = drm_mode->vsync_start;
330	    mode->VSyncEnd = drm_mode->vsync_end;
331	    mode->VTotal = drm_mode->vtotal;
332	    mode->Flags = drm_mode->flags;
333	    mode->HSkew = drm_mode->hskew;
334	    mode->VScan = drm_mode->vscan;
335	    mode->VRefresh = xf86ModeVRefresh(mode);
336	    mode->Private = (void *)drm_mode;
337	    mode->type = 0;
338	    if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
339		mode->type |= M_T_PREFERRED;
340	    if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
341		mode->type |= M_T_DRIVER;
342	    xf86SetModeDefaultName(mode);
343	    modes = xf86ModesAdd(modes, mode);
344	}
345    }
346
347    return modes;
348}
349
350static int
351output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
352{
353  //    modesettingPtr ms = modesettingPTR(output->scrn);
354    //    CustomizerPtr cust = ms->cust;
355
356#if 0
357    if (cust && cust->winsys_check_fb_size &&
358	!cust->winsys_check_fb_size(cust, pMode->HDisplay *
359				    output->scrn->bitsPerPixel / 8,
360				    pMode->VDisplay))
361	return MODE_BAD;
362#endif
363    return MODE_OK;
364}
365
366#ifdef RANDR_12_INTERFACE
367static Bool
368output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
369{
370    modesettingPtr ms = modesettingPTR(output->scrn);
371    struct output_private *vmwgfx_output = output->driver_private;
372    int i;
373
374    for (i = 0; i < vmwgfx_output->num_props; i++) {
375	struct output_prop *p = &vmwgfx_output->props[i];
376
377	if (p->atoms[0] != property)
378	    continue;
379
380	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
381	    uint32_t val;
382
383	    if (value->type != XA_INTEGER || value->format != 32 ||
384		    value->size != 1)
385		return FALSE;
386	    val = *(uint32_t *)value->data;
387	    p->value = val;
388	    drmModeConnectorSetProperty
389		(ms->fd, vmwgfx_output->drm_connector->connector_id,
390		 p->mode_prop->prop_id, (uint64_t)val);
391	    return TRUE;
392	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
393	    Atom	atom;
394	    const char	*name;
395	    int		j;
396
397	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
398		return FALSE;
399	    memcpy(&atom, value->data, 4);
400	    name = NameForAtom(atom);
401
402	    /* search for matching name string, then set its value down */
403	    for (j = 0; j < p->mode_prop->count_enums; j++) {
404		if (!strcmp(p->mode_prop->enums[j].name, name)) {
405		    p->value = p->mode_prop->enums[j].value;
406		    drmModeConnectorSetProperty
407			(ms->fd, vmwgfx_output->drm_connector->connector_id,
408			 p->mode_prop->prop_id, p->value);
409		    return TRUE;
410		}
411	    }
412	}
413    }
414
415    return TRUE;
416}
417#endif /* RANDR_12_INTERFACE */
418
419/**
420 * vmwgfx_output_property_scan - Update a single property on a single output
421 * @output: Pointer to the output to consider.
422 * @p: The property to update.
423 *
424 * Reads the property value from the drm connector corresponding to
425 * @output and notifies the RandR code of the new value, sending out an
426 * event if the new value doesn't match the old one. Finally updates @p
427 * with the new value.
428 */
429static Bool
430vmwgfx_output_property_scan(xf86OutputPtr output,
431			    struct output_prop *p)
432{
433    struct output_private *vmwgfx_output = output->driver_private;
434    uint32_t value = vmwgfx_output->drm_connector->prop_values[p->index];
435    int err = 0;
436
437#ifdef RANDR_13_INTERFACE
438    if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
439	err = RRChangeOutputProperty(output->randr_output,
440				     p->atoms[0], XA_INTEGER, 32,
441				     PropModeReplace, 1, &value,
442				     value != p->value, FALSE);
443    } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
444	int j;
445
446	/* search for matching name string, then set its value down */
447	for (j = 0; j < p->mode_prop->count_enums; j++) {
448	    if (p->mode_prop->enums[j].value == value)
449		break;
450	}
451
452	err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
453				     XA_ATOM, 32, PropModeReplace, 1,
454				     &p->atoms[j+1], value != p->value,
455				     FALSE);
456    }
457#endif /* RANDR_13_INTERFACE */
458    if (!err)
459	p->value = value;
460
461    return !err;
462}
463
464#ifdef RANDR_13_INTERFACE
465static Bool
466output_get_property(xf86OutputPtr output, Atom property)
467{
468    modesettingPtr ms = modesettingPTR(output->scrn);
469    struct output_private *vmwgfx_output = output->driver_private;
470    int i;
471
472    if (output->scrn->vtSema) {
473	drmModeConnectorPtr drm_connector =
474	    drmModeGetConnector(ms->fd,
475				vmwgfx_output->drm_connector->connector_id);
476
477	if (drm_connector) {
478	    drmModeFreeConnector(vmwgfx_output->drm_connector);
479	    vmwgfx_output->drm_connector = drm_connector;
480	}
481    }
482
483    for (i = 0; i < vmwgfx_output->num_props; i++) {
484	struct output_prop *p = &vmwgfx_output->props[i];
485	if (p->atoms[0] != property)
486	    continue;
487
488	return vmwgfx_output_property_scan(output, p);
489    }
490
491    return FALSE;
492}
493#endif /* RANDR_13_INTERFACE */
494
495static void
496output_destroy(xf86OutputPtr output)
497{
498    struct output_private *priv = output->driver_private;
499    int i;
500
501    for (i = 0; i < priv->num_props; i++) {
502	drmModeFreeProperty(priv->props[i].mode_prop);
503	free(priv->props[i].atoms);
504    }
505    free(priv->props);
506
507    drmModeFreeConnector(priv->drm_connector);
508    free(priv);
509    output->driver_private = NULL;
510}
511
512static const xf86OutputFuncsRec output_funcs = {
513    .create_resources = output_create_resources,
514#ifdef RANDR_12_INTERFACE
515    .set_property = output_set_property,
516#endif
517#ifdef RANDR_13_INTERFACE
518    .get_property = output_get_property,
519#endif
520    .dpms = output_dpms,
521    .detect = output_detect,
522
523    .get_modes = output_get_modes,
524    .mode_valid = output_mode_valid,
525    .destroy = output_destroy,
526};
527
528/**
529 * vmwgfx_output_explicit_overlap -- Check for explicit output overlaps
530 *
531 * This function returns TRUE iff the bounding box in screen space of an
532 * exlplicit output overlaps the bounding box in screen space of any other
533 * output.
534 */
535Bool
536vmwgfx_output_explicit_overlap(ScrnInfoPtr pScrn)
537{
538    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
539    xf86OutputPtr output;
540    ScreenPtr pScreen = pScrn->pScreen;
541    RegionRec output_union;
542    RegionRec cur_output;
543    RegionRec result;
544    xf86CrtcPtr crtc;
545    Bool overlap = FALSE;
546    int i;
547
548    (void) pScreen;
549    REGION_NULL(pScreen, &output_union);
550    REGION_NULL(pScreen, &cur_output);
551    REGION_NULL(pScreen, &result);
552
553    /*
554     * Collect a region of implicit outputs. These may overlap.
555     */
556    for (i = 0; i < config->num_output; i++) {
557	output = config->output[i];
558	crtc = output->crtc;
559
560	if (!crtc || !crtc->enabled || !vmwgfx_output_is_implicit(output))
561	    continue;
562
563	REGION_RESET(pScreen, &cur_output, &crtc->bounds);
564	REGION_UNION(pScreen, &output_union, &output_union, &cur_output);
565    }
566
567    /*
568     * Explicit outputs may not overlap any other output.
569     */
570    for (i = 0; i < config->num_output; i++) {
571	output = config->output[i];
572	crtc = output->crtc;
573
574	if (!crtc || !crtc->enabled || vmwgfx_output_is_implicit(output))
575	    continue;
576
577	REGION_RESET(pScreen, &cur_output, &crtc->bounds);
578	REGION_NULL(pScreen, &result);
579	REGION_INTERSECT(pScreen, &result, &output_union, &cur_output);
580	overlap = REGION_NOTEMPTY(vsaa->pScreen, &result);
581	if (overlap)
582	    break;
583
584	REGION_UNION(pScreen, &output_union, &output_union, &cur_output);
585    }
586
587    REGION_UNINIT(pScreen, &output_union);
588    REGION_UNINIT(pScreen, &cur_output);
589    REGION_UNINIT(pScreen, &result);
590
591    return overlap;
592}
593
594void
595xorg_output_init(ScrnInfoPtr pScrn)
596{
597    modesettingPtr ms = modesettingPTR(pScrn);
598    xf86OutputPtr output;
599    drmModeResPtr res;
600    drmModeConnectorPtr drm_connector = NULL;
601    drmModeEncoderPtr drm_encoder = NULL;
602    struct output_private *priv;
603    char name[32];
604    int c;
605
606    res = drmModeGetResources(ms->fd);
607    if (res == 0) {
608	DRV_ERROR("Failed drmModeGetResources\n");
609	return;
610    }
611
612    for (c = 0; c < res->count_connectors; c++) {
613	drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]);
614	if (!drm_connector)
615	    goto out;
616
617	if (drm_connector->connector_type >=
618	    sizeof(output_enum_list) / sizeof(output_enum_list[0]))
619	    drm_connector->connector_type = 0;
620
621	snprintf(name, 32, "%s%d",
622		 output_enum_list[drm_connector->connector_type],
623		 drm_connector->connector_type_id);
624
625
626	priv = calloc(sizeof(*priv), 1);
627	if (!priv) {
628	    continue;
629	}
630
631	output = xf86OutputCreate(pScrn, &output_funcs, name);
632	if (!output) {
633	    free(priv);
634	    continue;
635	}
636
637	priv->suggested_x = -1;
638	priv->suggested_y = -1;
639	priv->implicit_placement = -1;
640
641	drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
642	if (drm_encoder) {
643	    output->possible_crtcs = drm_encoder->possible_crtcs;
644	    output->possible_clones = drm_encoder->possible_clones;
645	    drmModeFreeEncoder(drm_encoder);
646	} else {
647	    output->possible_crtcs = 0;
648	    output->possible_clones = 0;
649	}
650	priv->c = c;
651	priv->drm_connector = drm_connector;
652	output->driver_private = priv;
653	output->subpixel_order = SubPixelHorizontalRGB;
654	output->interlaceAllowed = FALSE;
655	output->doubleScanAllowed = FALSE;
656    }
657
658  out:
659    drmModeFreeResources(res);
660}
661
662unsigned
663xorg_output_get_id(xf86OutputPtr output)
664{
665    struct output_private *priv = output->driver_private;
666    return priv->drm_connector->connector_id;
667}
668
669#ifdef HAVE_LIBUDEV
670
671/**
672 * vmwgfx_output_properties_scan - Update all properties on all outputs
673 * on this screen.
674 * @pScrn: Pointer to the ScrnInfo structure for this screen.
675 *
676 * Updates all connector info from DRM and then calls
677 * vmwgfx_output_property_scan() for all properties on all connectors.
678 */
679static void
680vmwgfx_output_properties_scan(ScrnInfoPtr pScrn)
681{
682    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
683    modesettingPtr ms = modesettingPTR(pScrn);
684    int i;
685
686    for (i = 0; i < config->num_output; i++) {
687	xf86OutputPtr output = config->output[i];
688	struct output_private *vmwgfx_output = output->driver_private;
689	int j;
690
691	if (output->scrn->vtSema) {
692	    int id = vmwgfx_output->drm_connector->connector_id;
693
694	    if (vmwgfx_output->drm_connector)
695		drmModeFreeConnector(vmwgfx_output->drm_connector);
696	    vmwgfx_output->drm_connector = drmModeGetConnector(ms->fd, id);
697	}
698
699	if (!vmwgfx_output->drm_connector)
700	    continue;
701
702	for (j = 0; j < vmwgfx_output->num_props; j++) {
703	    struct output_prop *p = &vmwgfx_output->props[j];
704
705	    (void) vmwgfx_output_property_scan(output, p);
706	}
707    }
708}
709
710/**
711 * vmwgfx_outputs_off - Mark all crtc / output pairs as disabled and save
712 * their configuration.
713 *
714 * @pScrn: Pointer to a ScrnInfo struct.
715 *
716 * Note that to commit this to the display system, a call to this function
717 * should be followed by a call to xf86DisableUnusedFunctions()
718 */
719void
720vmwgfx_outputs_off(ScrnInfoPtr pScrn)
721{
722    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
723    int i;
724
725    for (i = 0; i < config->num_output; ++i) {
726	xf86OutputPtr output = config->output[i];
727	struct output_private *vmwgfx_output = output->driver_private;
728
729	vmwgfx_output->saved_crtc = output->crtc;
730	if (output->crtc) {
731	    vmwgfx_output->saved_crtc_enabled = output->crtc->enabled;
732	    output->crtc->enabled = FALSE;
733	    output->crtc = NULL;
734	}
735    }
736}
737
738/**
739 * vmwgfx_outputs_on - Reset crtc / output pairs to a configuation saved
740 * using vmwgfx_output_off.
741 *
742 * @pScrn: Pointer to a ScrnInfo struct.
743 *
744 * Note that to commit the setup to the display system, a call to this
745 * function should be followed by a call to xf86SetDesiredModes().
746 */
747void
748vmwgfx_outputs_on(ScrnInfoPtr pScrn)
749{
750    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
751    int i;
752
753    for (i = 0; i < config->num_output; ++i) {
754	xf86OutputPtr output = config->output[i];
755	struct output_private *vmwgfx_output = output->driver_private;
756
757	if (vmwgfx_output->saved_crtc) {
758	    output->crtc = vmwgfx_output->saved_crtc;
759	    output->crtc->enabled = vmwgfx_output->saved_crtc_enabled;
760	}
761    }
762}
763
764/**
765 * vmwgfx_handle uevent - Property update callback
766 *
767 * @fd: File descriptor for the uevent
768 * @closure: Pointer to the driver-private per-screen data cast to a void *
769 */
770static void
771vmwgfx_handle_uevents(int fd, void *closure)
772{
773    ScrnInfoPtr scrn = closure;
774    modesettingPtr ms = modesettingPTR(scrn);
775    struct udev_device *dev;
776    ScreenPtr pScreen = xf86ScrnToScreen(scrn);
777
778    dev = udev_monitor_receive_device(ms->uevent_monitor);
779    if (!dev)
780	return;
781
782    /* Read new properties, connection status and preferred modes from DRM. */
783    vmwgfx_output_properties_scan(scrn);
784
785    if (pScreen)
786	RRGetInfo(pScreen, TRUE);
787
788    if (ms->autoLayout)
789	vmwgfx_layout_handler(scrn);
790
791    udev_device_unref(dev);
792}
793#endif  /* HAVE_LIBUDEV */
794
795/**
796 * vmwgfx_uevent_init - Initialize the property update monitor
797 *
798 * @scrn: Pointer to the ScrnInfo for this screen
799 * @ms: Pointer to the driver private per-screen data
800 */
801void vmwgfx_uevent_init(ScrnInfoPtr scrn, modesettingPtr ms)
802{
803#ifdef HAVE_LIBUDEV
804    struct udev *u;
805    struct udev_monitor *mon;
806
807    u = udev_new();
808    if (!u)
809	return;
810    mon = udev_monitor_new_from_netlink(u, "udev");
811    if (!mon) {
812	udev_unref(u);
813	return;
814    }
815
816    if (udev_monitor_filter_add_match_subsystem_devtype(mon,
817							"drm",
818							"drm_minor") < 0 ||
819	udev_monitor_enable_receiving(mon) < 0) {
820	udev_monitor_unref(mon);
821	udev_unref(u);
822	return;
823    }
824
825    ms->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
826					       vmwgfx_handle_uevents,
827					       scrn);
828
829    ms->uevent_monitor = mon;
830#endif  /* HAVE_LIBUDEV */
831}
832
833/**
834 * vmwgfx_uevent_fini - Close the property update monitor
835 *
836 * @scrn: Pointer to the ScrnInfo for this screen
837 * @ms: Pointer to the driver private per-screen data
838 */
839void vmwgfx_uevent_fini(ScrnInfoPtr scrn, modesettingPtr ms)
840{
841#ifdef HAVE_LIBUDEV
842    if (ms->uevent_handler) {
843	struct udev *u = udev_monitor_get_udev(ms->uevent_monitor);
844
845	xf86RemoveGeneralHandler(ms->uevent_handler);
846
847	udev_monitor_unref(ms->uevent_monitor);
848	udev_unref(u);
849    }
850#endif /* HAVE_LIBUDEV */
851}
852
853/* vim: set sw=4 ts=8 sts=4: */
854