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