via_kms.c revision 963d66ac
1/* 2 * Copyright © 2007 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Dave Airlie <airlied@redhat.com> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <errno.h> 33#include <sys/ioctl.h> 34#include <sys/mman.h> 35#include "xf86str.h" 36#include "X11/Xatom.h" 37#include "micmap.h" 38#include "xf86cmap.h" 39#include "xf86DDC.h" 40 41#include <xf86drm.h> 42#include "xf86Crtc.h" 43#include "via_driver.h" 44 45/* DPMS */ 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 53xf86CrtcPtr 54window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h) 55{ 56 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 57 int largest = 0, area = 0, i; 58 BoxRec crtc_area, overlap; 59 xf86CrtcPtr best = NULL; 60 61 for (i = 0; i < xf86_config->num_crtc; i++) { 62 xf86CrtcPtr crtc = xf86_config->crtc[i]; 63 64 if (crtc->enabled) { 65 crtc_area.x1 = crtc->x; 66 crtc_area.x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 67 crtc_area.y1 = crtc->y; 68 crtc_area.y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 69 overlap.x1 = crtc_area.x1 > x ? crtc_area.x1 : x; 70 overlap.x2 = crtc_area.x2 < x + w ? crtc_area.x2 : x + w; 71 overlap.y1 = crtc_area.y1 > y ? crtc_area.y1 : y; 72 overlap.y2 = crtc_area.y2 < y ? crtc_area.y2 : y + h; 73 74 if (overlap.x1 >= overlap.x2 || overlap.y1 >= overlap.y2) 75 overlap.x1 = overlap.x2 = overlap.y1 = overlap.y2 = 0; 76 77 area = (overlap.x2 - overlap.x1) * (overlap.y2 - overlap.y1); 78 if (area > largest) { 79 area = largest; 80 best = crtc; 81 } 82 } 83 } 84 return best; 85} 86 87static void 88drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, 89 DisplayModePtr mode) 90{ 91 memset(mode, 0, sizeof(DisplayModeRec)); 92 mode->status = MODE_OK; 93 94 mode->Clock = kmode->clock; 95 96 mode->HDisplay = kmode->hdisplay; 97 mode->HSyncStart = kmode->hsync_start; 98 mode->HSyncEnd = kmode->hsync_end; 99 mode->HTotal = kmode->htotal; 100 mode->HSkew = kmode->hskew; 101 102 mode->VDisplay = kmode->vdisplay; 103 mode->VSyncStart = kmode->vsync_start; 104 mode->VSyncEnd = kmode->vsync_end; 105 mode->VTotal = kmode->vtotal; 106 mode->VScan = kmode->vscan; 107 108 mode->Flags = kmode->flags; //& FLAG_BITS; 109 mode->name = strdup(kmode->name); 110 111 if (kmode->type & DRM_MODE_TYPE_DRIVER) 112 mode->type = M_T_DRIVER; 113 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 114 mode->type |= M_T_PREFERRED; 115 xf86SetModeCrtc(mode, pScrn->adjustFlags); 116} 117 118static void 119drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, 120 DisplayModePtr mode) 121{ 122 memset(kmode, 0, sizeof(*kmode)); 123 124 kmode->clock = mode->Clock; 125 kmode->hdisplay = mode->HDisplay; 126 kmode->hsync_start = mode->HSyncStart; 127 kmode->hsync_end = mode->HSyncEnd; 128 kmode->htotal = mode->HTotal; 129 kmode->hskew = mode->HSkew; 130 131 kmode->vdisplay = mode->VDisplay; 132 kmode->vsync_start = mode->VSyncStart; 133 kmode->vsync_end = mode->VSyncEnd; 134 kmode->vtotal = mode->VTotal; 135 kmode->vscan = mode->VScan; 136 137 kmode->flags = mode->Flags; //& FLAG_BITS; 138 if (mode->name) 139 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 140 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 141} 142 143static void 144drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 145{ 146#if 0 147 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 148 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 149 drmmode_ptr drmmode = drmmode_crtc->drmmode; 150 151 /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */ 152 if (mode == DPMSModeOff) { 153 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 154 0, 0, 0, NULL, 0, NULL); 155 } 156#endif 157} 158 159static Bool 160drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 161 Rotation rotation, int x, int y) 162{ 163 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 164 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 165 drmmode_ptr drmmode = drmmode_crtc->drmmode; 166 ScrnInfoPtr pScrn = crtc->scrn; 167 int output_count = 0, ret, i; 168 uint32_t *output_ids = NULL; 169 drmModeModeInfo kmode; 170 171 if (!mode || !xf86CrtcRotate(crtc)) 172 return FALSE; 173 174 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 175 if (!output_ids) 176 return FALSE; 177 178 for (i = 0; i < xf86_config->num_output; i++) { 179 xf86OutputPtr output = xf86_config->output[i]; 180 drmmode_output_private_ptr drmmode_output; 181 182 if (output->crtc != crtc) 183 continue; 184 185 drmmode_output = output->driver_private; 186 output_ids[output_count] = drmmode_output->mode_output->connector_id; 187 output_count++; 188 } 189 190 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 191 192 if (drmmode->fb_id == 0) { 193 ret = drmModeAddFB(drmmode->fd, pScrn->virtualX, pScrn->virtualY, 194 pScrn->depth, pScrn->bitsPerPixel, 195 drmmode->front_bo->pitch, 196 drmmode->front_bo->handle, 197 &drmmode->fb_id); 198 if (ret < 0) { 199 ErrorF("failed to add fb %d\n", ret); 200 goto done; 201 } 202 } 203 204 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 205 drmmode->fb_id, x, y, output_ids, output_count, &kmode); 206 if (ret) { 207 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set mode: %s", 208 strerror(-ret)); 209 goto done; 210 } 211 212 if (crtc->scrn->pScreen) 213 xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); 214 215 /* go through all the outputs and force DPMS them back on? */ 216 for (i = 0; i < xf86_config->num_output; i++) { 217 xf86OutputPtr output = xf86_config->output[i]; 218 219 if (output->crtc != crtc) 220 continue; 221 222 output->funcs->dpms(output, DPMSModeOn); 223 } 224 225#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 226 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 227 crtc->gamma_blue, crtc->gamma_size); 228#endif 229 230 if (pScrn->pScreen && drmmode->hwcursor) 231 xf86_reload_cursors(pScrn->pScreen); 232done: 233 free(output_ids); 234 return (ret < 0 ? FALSE : TRUE); 235} 236 237static void 238drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 239{ 240} 241 242static void 243drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 244{ 245 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 246 drmmode_ptr drmmode = drmmode_crtc->drmmode; 247 248 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 249} 250 251static void 252drmmode_hide_cursor (xf86CrtcPtr crtc) 253{ 254 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 255 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 256 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 257 drmmode_ptr drmmode = drmmode_crtc->drmmode; 258 259 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 260 cursor_info->MaxWidth, cursor_info->MaxHeight); 261} 262 263static void 264drmmode_show_cursor (xf86CrtcPtr crtc) 265{ 266 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 267 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 268 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 269 uint32_t handle = drmmode_crtc->cursor_bo->handle; 270 drmmode_ptr drmmode = drmmode_crtc->drmmode; 271 272 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 273 cursor_info->MaxWidth, cursor_info->MaxHeight); 274} 275 276static void 277drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 278{ 279 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 280 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 281 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 282 uint32_t handle = drmmode_crtc->cursor_bo->handle, *ptr; 283 284 /* cursor should be mapped already */ 285 ptr = drm_bo_map(crtc->scrn, drmmode_crtc->cursor_bo); 286 memset(ptr, 0x00, drmmode_crtc->cursor_bo->size); 287 memcpy(ptr, image, drmmode_crtc->cursor_bo->size); 288 drm_bo_unmap(crtc->scrn, drmmode_crtc->cursor_bo); 289 290 if (drmModeSetCursor(drmmode_crtc->drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 291 handle, cursor_info->MaxWidth, cursor_info->MaxHeight)) { 292 drmmode_ptr drmmode = drmmode_crtc->drmmode; 293 294 cursor_info->MaxWidth = cursor_info->MaxHeight = 0; 295 drmmode->hwcursor = FALSE; 296 } 297} 298 299static void 300drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 301 uint16_t *blue, int size) 302{ 303 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 304 drmmode_ptr drmmode = drmmode_crtc->drmmode; 305 306 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 307 size, red, green, blue); 308} 309 310static const xf86CrtcFuncsRec drmmode_crtc_funcs = { 311 .dpms = drmmode_crtc_dpms, 312 .set_mode_major = drmmode_set_mode_major, 313 .set_cursor_colors = drmmode_set_cursor_colors, 314 .set_cursor_position = drmmode_set_cursor_position, 315 .show_cursor = drmmode_show_cursor, 316 .hide_cursor = drmmode_hide_cursor, 317 .load_cursor_argb = drmmode_load_cursor_argb, 318 .gamma_set = drmmode_crtc_gamma_set, 319 .destroy = NULL, 320}; 321 322static void 323drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 324{ 325 drmmode_crtc_private_ptr drmmode_crtc; 326 xf86CrtcPtr crtc; 327 328 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 329 if (crtc == NULL) 330 return; 331 332 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 333 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); 334 drmmode_crtc->drmmode = drmmode; 335 crtc->driver_private = drmmode_crtc; 336} 337 338/* 339 * Handle KMS xf86Outputs 340 */ 341static Bool 342drmmode_property_ignore(drmModePropertyPtr prop) 343{ 344 if (!prop) 345 return TRUE; 346 347 /* ignore blob prop */ 348 if (prop->flags & DRM_MODE_PROP_BLOB) 349 return TRUE; 350 351 /* ignore standard property */ 352 if (!strcmp(prop->name, "EDID") || 353 !strcmp(prop->name, "DPMS")) 354 return TRUE; 355 356 return FALSE; 357} 358 359static void 360drmmode_output_dpms(xf86OutputPtr output, int mode) 361{ 362 drmmode_output_private_ptr drmmode_output = output->driver_private; 363 drmModeConnectorPtr koutput = drmmode_output->mode_output; 364 drmmode_ptr drmmode = drmmode_output->drmmode; 365 366 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 367 drmmode_output->dpms_enum_id, mode); 368 return; 369} 370 371static void 372drmmode_output_create_resources(xf86OutputPtr output) 373{ 374 drmmode_output_private_ptr drmmode_output = output->driver_private; 375 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 376 drmmode_ptr drmmode = drmmode_output->drmmode; 377 drmModePropertyPtr drmmode_prop; 378 int i, j, err; 379 380 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 381 if (!drmmode_output->props) 382 return; 383 384 drmmode_output->num_props = 0; 385 for (i = 0, j = 0; i < mode_output->count_props; i++) { 386 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 387 388 if (drmmode_property_ignore(drmmode_prop)) { 389 drmModeFreeProperty(drmmode_prop); 390 continue; 391 } 392 drmmode_output->props[j].mode_prop = drmmode_prop; 393 drmmode_output->props[j].value = mode_output->prop_values[i]; 394 drmmode_output->num_props++; 395 j++; 396 } 397 398 for (i = 0; i < drmmode_output->num_props; i++) { 399 drmmode_prop_ptr p = &drmmode_output->props[i]; 400 drmmode_prop = p->mode_prop; 401 402 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 403 INT32 range[2]; 404 INT32 value = p->value; 405 406 p->num_atoms = 1; 407 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 408 if (!p->atoms) 409 continue; 410 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 411 range[0] = drmmode_prop->values[0]; 412 range[1] = drmmode_prop->values[1]; 413 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 414 FALSE, TRUE, 415 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 416 2, range); 417 if (err != 0) { 418 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 419 "RRConfigureOutputProperty error, %d\n", err); 420 } 421 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 422 XA_INTEGER, 32, PropModeReplace, 1, 423 &value, FALSE, TRUE); 424 if (err != 0) { 425 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 426 "RRChangeOutputProperty error, %d\n", err); 427 } 428 429 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 430 p->num_atoms = drmmode_prop->count_enums + 1; 431 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 432 if (!p->atoms) 433 continue; 434 435 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 436 for (j = 1; j <= drmmode_prop->count_enums; j++) { 437 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 438 439 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 440 } 441 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 442 FALSE, FALSE, 443 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 444 p->num_atoms - 1, (INT32 *)&p->atoms[1]); 445 if (err != 0) { 446 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 447 "RRConfigureOutputProperty error, %d\n", err); 448 } 449 450 for (j = 0; j < drmmode_prop->count_enums; j++) 451 if (drmmode_prop->enums[j].value == p->value) 452 break; 453 454 /* there's always a matching value */ 455 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 456 XA_ATOM, 32, PropModeReplace, 1, 457 &p->atoms[j+1], FALSE, TRUE); 458 if (err != 0) { 459 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 460 "RRChangeOutputProperty error, %d\n", err); 461 } 462 } 463 } 464} 465 466static Bool 467drmmode_output_set_property(xf86OutputPtr output, Atom property, 468 RRPropertyValuePtr value) 469{ 470 drmmode_output_private_ptr drmmode_output = output->driver_private; 471 drmmode_ptr drmmode = drmmode_output->drmmode; 472 int i; 473 474 for (i = 0; i < drmmode_output->num_props; i++) { 475 drmmode_prop_ptr p = &drmmode_output->props[i]; 476 477 if (p->atoms[0] != property) 478 continue; 479 480 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 481 uint32_t val; 482 483 if (value->type != XA_INTEGER || value->format != 32 || 484 value->size != 1) 485 return FALSE; 486 val = *(uint32_t *)value->data; 487 488 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 489 p->mode_prop->prop_id, (uint64_t)val); 490 return TRUE; 491 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 492 const char *name; 493 Atom atom; 494 int j; 495 496 if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 497 return FALSE; 498 memcpy(&atom, value->data, 4); 499 name = NameForAtom(atom); 500 501 /* search for matching name string, then set its value down */ 502 for (j = 0; j < p->mode_prop->count_enums; j++) { 503 if (!strcmp(p->mode_prop->enums[j].name, name)) { 504 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 505 p->mode_prop->prop_id, p->mode_prop->enums[j].value); 506 return TRUE; 507 } 508 } 509 } 510 } 511 return TRUE; 512} 513 514static Bool 515drmmode_output_get_property(xf86OutputPtr output, Atom property) 516{ 517 return TRUE; 518} 519 520static xf86OutputStatus 521drmmode_output_detect(xf86OutputPtr output) 522{ 523 /* go to the hw and retrieve a new output struct */ 524 drmmode_output_private_ptr drmmode_output = output->driver_private; 525 drmmode_ptr drmmode = drmmode_output->drmmode; 526 xf86OutputStatus status; 527 528 drmModeFreeConnector(drmmode_output->mode_output); 529 drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 530 531 switch (drmmode_output->mode_output->connection) { 532 case DRM_MODE_CONNECTED: 533 status = XF86OutputStatusConnected; 534 break; 535 case DRM_MODE_DISCONNECTED: 536 status = XF86OutputStatusDisconnected; 537 break; 538 default: 539 case DRM_MODE_UNKNOWNCONNECTION: 540 status = XF86OutputStatusUnknown; 541 break; 542 } 543 return status; 544} 545 546static Bool 547drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 548{ 549 return MODE_OK; 550} 551 552static DisplayModePtr 553drmmode_output_get_modes(xf86OutputPtr output) 554{ 555 drmmode_output_private_ptr drmmode_output = output->driver_private; 556 drmModeConnectorPtr koutput = drmmode_output->mode_output; 557 drmmode_ptr drmmode = drmmode_output->drmmode; 558 DisplayModePtr Modes = NULL, Mode; 559 drmModePropertyPtr props; 560 xf86MonPtr mon = NULL; 561 int i; 562 563 /* look for an EDID property */ 564 for (i = 0; i < koutput->count_props; i++) { 565 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 566 if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 567 if (!strcmp(props->name, "EDID")) { 568 if (drmmode_output->edid_blob) 569 drmModeFreePropertyBlob(drmmode_output->edid_blob); 570 drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 571 } 572 drmModeFreeProperty(props); 573 } 574 } 575 576 if (drmmode_output->edid_blob) { 577 mon = xf86InterpretEDID(output->scrn->scrnIndex, 578 drmmode_output->edid_blob->data); 579 if (mon && drmmode_output->edid_blob->length > 128) 580 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 581 } 582 xf86OutputSetEDID(output, mon); 583 584 /* modes should already be available */ 585 for (i = 0; i < koutput->count_modes; i++) { 586 Mode = xnfalloc(sizeof(DisplayModeRec)); 587 588 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 589 Modes = xf86ModesAdd(Modes, Mode); 590 591 } 592 return Modes; 593} 594 595static void 596drmmode_output_destroy(xf86OutputPtr output) 597{ 598 drmmode_output_private_ptr drmmode_output = output->driver_private; 599 int i; 600 601 if (drmmode_output->edid_blob) 602 drmModeFreePropertyBlob(drmmode_output->edid_blob); 603 604 for (i = 0; i < drmmode_output->num_props; i++) { 605 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 606 free(drmmode_output->props[i].atoms); 607 } 608 609 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 610 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 611 free(drmmode_output->mode_encoders); 612 } 613 free(drmmode_output->props); 614 drmModeFreeConnector(drmmode_output->mode_output); 615 free(drmmode_output); 616 output->driver_private = NULL; 617} 618 619static const xf86OutputFuncsRec drmmode_output_funcs = { 620 .dpms = drmmode_output_dpms, 621 .create_resources = drmmode_output_create_resources, 622#ifdef RANDR_12_INTERFACE 623 .set_property = drmmode_output_set_property, 624 .get_property = drmmode_output_get_property, 625#endif 626 .detect = drmmode_output_detect, 627 .mode_valid = drmmode_output_mode_valid, 628 .get_modes = drmmode_output_get_modes, 629 .destroy = drmmode_output_destroy 630}; 631 632static int subpixel_conv_table[7] = { 633 0, 634 SubPixelUnknown, 635 SubPixelHorizontalRGB, 636 SubPixelHorizontalBGR, 637 SubPixelVerticalRGB, 638 SubPixelVerticalBGR, 639 SubPixelNone 640}; 641 642const char *output_names[] = { 643 "None", 644 "VGA", 645 "DVI", 646 "DVI", 647 "DVI", 648 "Composite", 649 "S-video", 650 "LVDS", 651 "CTV", 652 "DIN", 653 "DisplayPort", 654 "HDMI", 655 "HDMI", 656 "TV", 657 "eDP" 658}; 659 660static void 661drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 662{ 663 xf86OutputPtr output; 664 drmModeConnectorPtr koutput; 665 drmModeEncoderPtr *kencoders = NULL; 666 drmmode_output_private_ptr drmmode_output; 667 drmModePropertyPtr props; 668 char name[32]; 669 int i; 670 671 koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); 672 if (!koutput) 673 return; 674 675 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 676 if (!kencoders) { 677 goto out_free_encoders; 678 } 679 680 for (i = 0; i < koutput->count_encoders; i++) { 681 kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 682 if (!kencoders[i]) { 683 goto out_free_encoders; 684 } 685 } 686 687 /* need to do smart conversion here for compat with non-kms ATI driver */ 688 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 689 690 output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 691 if (!output) { 692 goto out_free_encoders; 693 } 694 695 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 696 if (!drmmode_output) { 697 xf86OutputDestroy(output); 698 goto out_free_encoders; 699 } 700 701 drmmode_output->output_id = drmmode->mode_res->connectors[num]; 702 drmmode_output->mode_output = koutput; 703 drmmode_output->mode_encoders = kencoders; 704 drmmode_output->drmmode = drmmode; 705 output->mm_width = koutput->mmWidth; 706 output->mm_height = koutput->mmHeight; 707 708 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 709 output->interlaceAllowed = TRUE; 710 output->doubleScanAllowed = TRUE; 711 output->driver_private = drmmode_output; 712 713 output->possible_crtcs = 0x7f; 714 for (i = 0; i < koutput->count_encoders; i++) 715 output->possible_crtcs &= kencoders[i]->possible_crtcs; 716 717 /* work out the possible clones later */ 718 output->possible_clones = 0; 719 720 for (i = 0; i < koutput->count_props; i++) { 721 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 722 if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 723 if (!strcmp(props->name, "DPMS")) { 724 drmmode_output->dpms_enum_id = koutput->props[i]; 725 drmModeFreeProperty(props); 726 break; 727 } 728 drmModeFreeProperty(props); 729 } 730 } 731 732 return; 733out_free_encoders: 734 if (kencoders){ 735 for (i = 0; i < koutput->count_encoders; i++) 736 drmModeFreeEncoder(kencoders[i]); 737 free(kencoders); 738 } 739 drmModeFreeConnector(koutput); 740} 741 742uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 743{ 744 drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 745 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 746 xf86OutputPtr clone_output; 747 int index_mask = 0, i; 748 749 if (drmmode_output->enc_clone_mask == 0) 750 return index_mask; 751 752 for (i = 0; i < xf86_config->num_output; i++) { 753 clone_output = xf86_config->output[i]; 754 clone_drmout = clone_output->driver_private; 755 if (output == clone_output) 756 continue; 757 if (clone_drmout->enc_mask == 0) 758 continue; 759 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 760 index_mask |= (1 << i); 761 } 762 return index_mask; 763} 764 765static void 766drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 767{ 768 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 769 int i, j; 770 771 for (i = 0; i < xf86_config->num_output; i++) { 772 xf86OutputPtr output = xf86_config->output[i]; 773 drmmode_output_private_ptr drmmode_output; 774 775 drmmode_output = output->driver_private; 776 drmmode_output->enc_clone_mask = 0xff; 777 /* and all the possible encoder clones for this output together */ 778 for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) { 779 int k; 780 781 for (k = 0; k < drmmode->mode_res->count_encoders; k++) { 782 if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 783 drmmode_output->enc_mask |= (1 << k); 784 } 785 786 drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 787 } 788 } 789 790 for (i = 0; i < xf86_config->num_output; i++) { 791 xf86OutputPtr output = xf86_config->output[i]; 792 output->possible_clones = find_clones(scrn, output); 793 } 794} 795 796Bool KMSCrtcInit(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 797{ 798 int i; 799 800 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "KMSCrtcInit\n")); 801 802 drmmode->scrn = pScrn; 803 drmmode->mode_res = drmModeGetResources(drmmode->fd); 804 if (!drmmode->mode_res) 805 return FALSE; 806 807 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); 808 for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 809 if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i) 810 drmmode_crtc_init(pScrn, drmmode, i); 811 812 for (i = 0; i < drmmode->mode_res->count_connectors; i++) 813 drmmode_output_init(pScrn, drmmode, i); 814 815 /* workout clones */ 816 drmmode_clones_init(pScrn, drmmode); 817 return TRUE; 818} 819 820#ifdef HAVE_UDEV 821static void 822drmmode_handle_uevents(int fd, void *closure) 823{ 824 drmmode_ptr drmmode = closure; 825 ScrnInfoPtr scrn = drmmode->scrn; 826 struct udev_device *dev; 827 828 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 829 if (!dev) 830 return; 831 832 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 833 udev_device_unref(dev); 834} 835#endif 836 837void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 838{ 839#ifdef HAVE_UDEV 840 struct udev_monitor *mon; 841 struct udev *u; 842 843 u = udev_new(); 844 if (!u) 845 return; 846 847 mon = udev_monitor_new_from_netlink(u, "udev"); 848 if (!mon) { 849 udev_unref(u); 850 return; 851 } 852 853 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0 || 854 udev_monitor_enable_receiving(mon) < 0) { 855 udev_monitor_unref(mon); 856 udev_unref(u); 857 return; 858 } 859 860 drmmode->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon), 861 drmmode_handle_uevents, 862 drmmode); 863 drmmode->uevent_monitor = mon; 864#endif 865} 866 867void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 868{ 869#ifdef HAVE_UDEV 870 if (drmmode->uevent_handler) { 871 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 872 873 xf86RemoveGeneralHandler(drmmode->uevent_handler); 874 875 udev_monitor_unref(drmmode->uevent_monitor); 876 udev_unref(u); 877 } 878#endif 879} 880