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#ifdef XF86DRM_MODE 34 35#include <sys/ioctl.h> 36#include "qxl_drmmode.h" 37#include "X11/Xatom.h" 38#include "xf86DDC.h" 39#include <X11/extensions/dpmsconst.h> 40#include <cursorstr.h> 41 42#include "qxl.h" 43#include "qxl_surface.h" 44 45static void drmmode_show_cursor (xf86CrtcPtr crtc); 46 47static void 48drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 49 drmModeModeInfo *kmode, 50 DisplayModePtr mode) 51{ 52 memset(mode, 0, sizeof(DisplayModeRec)); 53 mode->status = MODE_OK; 54 55 mode->Clock = kmode->clock; 56 57 mode->HDisplay = kmode->hdisplay; 58 mode->HSyncStart = kmode->hsync_start; 59 mode->HSyncEnd = kmode->hsync_end; 60 mode->HTotal = kmode->htotal; 61 mode->HSkew = kmode->hskew; 62 63 mode->VDisplay = kmode->vdisplay; 64 mode->VSyncStart = kmode->vsync_start; 65 mode->VSyncEnd = kmode->vsync_end; 66 mode->VTotal = kmode->vtotal; 67 mode->VScan = kmode->vscan; 68 69 mode->Flags = kmode->flags; //& FLAG_BITS; 70 mode->name = strdup(kmode->name); 71 72 if (kmode->type & DRM_MODE_TYPE_DRIVER) 73 mode->type = M_T_DRIVER; 74 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 75 mode->type |= M_T_PREFERRED; 76 xf86SetModeCrtc (mode, scrn->adjustFlags); 77} 78 79static void 80drmmode_ConvertToKMode(ScrnInfoPtr scrn, 81 drmModeModeInfo *kmode, 82 DisplayModePtr mode) 83{ 84 memset(kmode, 0, sizeof(*kmode)); 85 86 kmode->clock = mode->Clock; 87 kmode->hdisplay = mode->HDisplay; 88 kmode->hsync_start = mode->HSyncStart; 89 kmode->hsync_end = mode->HSyncEnd; 90 kmode->htotal = mode->HTotal; 91 kmode->hskew = mode->HSkew; 92 93 kmode->vdisplay = mode->VDisplay; 94 kmode->vsync_start = mode->VSyncStart; 95 kmode->vsync_end = mode->VSyncEnd; 96 kmode->vtotal = mode->VTotal; 97 kmode->vscan = mode->VScan; 98 99 kmode->flags = mode->Flags; //& FLAG_BITS; 100 if (mode->name) 101 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 102 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 103 104} 105 106 107static void 108drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 109{ 110 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 111// drmmode_ptr drmmode = drmmode_crtc->drmmode; 112 113 drmmode_crtc->dpms_mode = mode; 114 115#if 0 116 /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */ 117 if (mode == DPMSModeOff) { 118// drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 119// 0, 0, 0, NULL, 0, NULL); 120 } 121#endif 122} 123 124static Bool 125drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 126 Rotation rotation, int x, int y) 127{ 128 ScrnInfoPtr pScrn = crtc->scrn; 129 CursorPtr cursor; 130 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 131 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 132 drmmode_ptr drmmode = drmmode_crtc->drmmode; 133 int saved_x, saved_y; 134 Rotation saved_rotation; 135 DisplayModeRec saved_mode; 136 uint32_t *output_ids; 137 int output_count = 0; 138 Bool ret = TRUE; 139 int i; 140 int fb_id; 141 drmModeModeInfo kmode; 142 int pitch; 143 int height; 144 qxl_screen_t *qxl = crtc->scrn->driverPrivate; 145 146 pitch = pScrn->displayWidth * ((pScrn->bitsPerPixel + 7) >> 3); 147 height = pScrn->virtualY; 148 if (drmmode->fb_id == 0) { 149 ret = drmModeAddFB(drmmode->fd, 150 pScrn->virtualX, height, 151 pScrn->depth, pScrn->bitsPerPixel, 152 pitch, 153 qxl_kms_bo_get_handle(qxl->primary->bo), 154 &drmmode->fb_id); 155 if (ret < 0) { 156 ErrorF("failed to add fb\n"); 157 return FALSE; 158 } 159 } 160 161 saved_mode = crtc->mode; 162 saved_x = crtc->x; 163 saved_y = crtc->y; 164 saved_rotation = crtc->rotation; 165 166 if (mode) { 167 crtc->mode = *mode; 168 crtc->x = x; 169 crtc->y = y; 170 crtc->rotation = rotation; 171#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0) 172 crtc->transformPresent = FALSE; 173#endif 174 } 175 176 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 177 if (!output_ids) { 178 ret = FALSE; 179 goto done; 180 } 181 182 if (mode) { 183 for (i = 0; i < xf86_config->num_output; i++) { 184 xf86OutputPtr output = xf86_config->output[i]; 185 drmmode_output_private_ptr drmmode_output; 186 187 if (output->crtc != crtc) 188 continue; 189 190 drmmode_output = output->driver_private; 191 output_ids[output_count] = drmmode_output->mode_output->connector_id; 192 output_count++; 193 } 194 195#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 196 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 197 crtc->gamma_blue, crtc->gamma_size); 198#endif 199 200 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 201 202 fb_id = drmmode->fb_id; 203 if (drmmode_crtc->rotate_fb_id) { 204 fb_id = drmmode_crtc->rotate_fb_id; 205 x = y = 0; 206 } 207 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 208 fb_id, x, y, output_ids, output_count, &kmode); 209 if (ret) { 210 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 211 "failed to set mode: %s", strerror(-ret)); 212 return FALSE; 213 } else { 214 ret = TRUE; 215 } 216 217 if (crtc->scrn->pScreen) 218 xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); 219 /* go through all the outputs and force DPMS them back on? */ 220 for (i = 0; i < xf86_config->num_output; i++) { 221 xf86OutputPtr output = xf86_config->output[i]; 222 223 if (output->crtc != crtc) 224 continue; 225 226 output->funcs->dpms(output, DPMSModeOn); 227 } 228 } 229 230#if 0 231 if (pScrn->pScreen && 232 !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 233 xf86_reload_cursors(pScrn->pScreen); 234#endif 235 236done: 237 if (!ret) { 238 crtc->x = saved_x; 239 crtc->y = saved_y; 240 crtc->rotation = saved_rotation; 241 crtc->mode = saved_mode; 242 } 243#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 244 else 245 crtc->active = TRUE; 246#endif 247 248 cursor = xf86_config->cursor; 249 if (cursor) 250 drmmode_show_cursor(crtc); 251 252 return ret; 253} 254 255static void 256drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 257{ 258 259} 260 261static void 262drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 263{ 264 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 265 drmmode_ptr drmmode = drmmode_crtc->drmmode; 266 267 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 268} 269 270static void 271drmmode_show_cursor (xf86CrtcPtr crtc) 272{ 273 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 274 drmmode_ptr drmmode = drmmode_crtc->drmmode; 275 uint32_t handle = qxl_kms_bo_get_handle(drmmode_crtc->cursor_bo); 276 static Bool use_set_cursor2 = TRUE; 277 278 if (use_set_cursor2) { 279 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 280 CursorPtr cursor = xf86_config->cursor; 281 int ret; 282 ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64, cursor->bits->xhot, cursor->bits->yhot); 283 if (ret == -EINVAL) 284 use_set_cursor2 = FALSE; 285 else 286 return; 287 } 288 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64); 289} 290 291static void 292drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 293{ 294 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 295 int i; 296 uint32_t *ptr; 297 298 /* cursor should be mapped already */ 299 ptr = (uint32_t *)(drmmode_crtc->cursor_ptr); 300 301 for (i = 0; i < 64 * 64; i++) 302 ptr[i] = image[i]; 303 304 drmmode_show_cursor(crtc); 305} 306 307static void 308drmmode_hide_cursor (xf86CrtcPtr crtc) 309{ 310 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 311 drmmode_ptr drmmode = drmmode_crtc->drmmode; 312 313 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64); 314} 315 316static void 317drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 318 uint16_t *blue, int size) 319{ 320 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 321 drmmode_ptr drmmode = drmmode_crtc->drmmode; 322 323 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 324 size, red, green, blue); 325} 326static const xf86CrtcFuncsRec drmmode_crtc_funcs = { 327 .dpms = drmmode_crtc_dpms, 328 .set_mode_major = drmmode_set_mode_major, 329 .set_cursor_colors = drmmode_set_cursor_colors, 330 .set_cursor_position = drmmode_set_cursor_position, 331 .show_cursor = drmmode_show_cursor, 332 .hide_cursor = drmmode_hide_cursor, 333 .load_cursor_argb = drmmode_load_cursor_argb, 334 335 .gamma_set = drmmode_crtc_gamma_set, 336 .destroy = NULL, /* XXX */ 337}; 338 339static void 340drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 341{ 342 qxl_screen_t *qxl = pScrn->driverPrivate; 343 xf86CrtcPtr crtc; 344 drmmode_crtc_private_ptr drmmode_crtc; 345 346 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 347 if (crtc == NULL) 348 return; 349 crtc->driverIsPerformingTransform = FALSE; 350 351 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 352 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); 353 drmmode_crtc->drmmode = drmmode; 354 crtc->driver_private = drmmode_crtc; 355 356 { 357 int cursor_size = 64*4*64; 358 359 drmmode_crtc->cursor_bo = qxl->bo_funcs->bo_alloc(qxl, cursor_size, "cursor"); 360 if (!drmmode_crtc->cursor_bo) { 361 ErrorF("failed to allocate cursor buffer\n"); 362 return; 363 } 364 365 drmmode_crtc->cursor_ptr = qxl->bo_funcs->bo_map(drmmode_crtc->cursor_bo); 366 } 367 368 return; 369} 370 371 372static xf86OutputStatus 373drmmode_output_detect(xf86OutputPtr output) 374{ 375 /* go to the hw and retrieve a new output struct */ 376 drmmode_output_private_ptr drmmode_output = output->driver_private; 377 drmmode_ptr drmmode = drmmode_output->drmmode; 378 xf86OutputStatus status; 379 drmModeFreeConnector(drmmode_output->mode_output); 380 381 drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 382 383 switch (drmmode_output->mode_output->connection) { 384 case DRM_MODE_CONNECTED: 385 status = XF86OutputStatusConnected; 386 break; 387 case DRM_MODE_DISCONNECTED: 388 status = XF86OutputStatusDisconnected; 389 break; 390 default: 391 case DRM_MODE_UNKNOWNCONNECTION: 392 status = XF86OutputStatusUnknown; 393 break; 394 } 395 return status; 396} 397 398static Bool 399drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 400{ 401 return MODE_OK; 402} 403 404static DisplayModePtr 405drmmode_output_get_modes(xf86OutputPtr output) 406{ 407 drmmode_output_private_ptr drmmode_output = output->driver_private; 408 drmModeConnectorPtr koutput = drmmode_output->mode_output; 409 drmmode_ptr drmmode = drmmode_output->drmmode; 410 int i; 411 DisplayModePtr Modes = NULL, Mode; 412 drmModePropertyPtr props; 413 xf86MonPtr mon = NULL; 414 415 /* look for an EDID property */ 416 for (i = 0; i < koutput->count_props; i++) { 417 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 418 if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 419 if (!strcmp(props->name, "EDID")) { 420 if (drmmode_output->edid_blob) 421 drmModeFreePropertyBlob(drmmode_output->edid_blob); 422 drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 423 } 424 drmModeFreeProperty(props); 425 } 426 } 427 428 if (drmmode_output->edid_blob) { 429 mon = xf86InterpretEDID(output->scrn->scrnIndex, 430 drmmode_output->edid_blob->data); 431 if (mon && drmmode_output->edid_blob->length > 128) 432 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 433 } 434 xf86OutputSetEDID(output, mon); 435 436 /* modes should already be available */ 437 for (i = 0; i < koutput->count_modes; i++) { 438 Mode = xnfalloc(sizeof(DisplayModeRec)); 439 440 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 441 Modes = xf86ModesAdd(Modes, Mode); 442 443 } 444 return Modes; 445} 446 447static void 448drmmode_output_destroy(xf86OutputPtr output) 449{ 450 drmmode_output_private_ptr drmmode_output = output->driver_private; 451 int i; 452 453 if (drmmode_output->edid_blob) 454 drmModeFreePropertyBlob(drmmode_output->edid_blob); 455 for (i = 0; i < drmmode_output->num_props; i++) { 456 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 457 free(drmmode_output->props[i].atoms); 458 } 459 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 460 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 461 free(drmmode_output->mode_encoders); 462 } 463 free(drmmode_output->props); 464 drmModeFreeConnector(drmmode_output->mode_output); 465 free(drmmode_output); 466 output->driver_private = NULL; 467} 468 469static void 470drmmode_output_dpms(xf86OutputPtr output, int mode) 471{ 472 drmmode_output_private_ptr drmmode_output = output->driver_private; 473 drmModeConnectorPtr koutput = drmmode_output->mode_output; 474 drmmode_ptr drmmode = drmmode_output->drmmode; 475 476 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 477 drmmode_output->dpms_enum_id, mode); 478 return; 479} 480 481 482static Bool 483drmmode_property_ignore(drmModePropertyPtr prop) 484{ 485 if (!prop) 486 return TRUE; 487 /* ignore blob prop */ 488 if (prop->flags & DRM_MODE_PROP_BLOB) 489 return TRUE; 490 /* ignore standard property */ 491 if (!strcmp(prop->name, "EDID") || 492 !strcmp(prop->name, "DPMS")) 493 return TRUE; 494 495 return FALSE; 496} 497 498static void 499drmmode_output_create_resources(xf86OutputPtr output) 500{ 501 drmmode_output_private_ptr drmmode_output = output->driver_private; 502 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 503 drmmode_ptr drmmode = drmmode_output->drmmode; 504 drmModePropertyPtr drmmode_prop; 505 int i, j, err; 506 507 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 508 if (!drmmode_output->props) 509 return; 510 511 drmmode_output->num_props = 0; 512 for (i = 0, j = 0; i < mode_output->count_props; i++) { 513 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 514 if (drmmode_property_ignore(drmmode_prop)) { 515 drmModeFreeProperty(drmmode_prop); 516 continue; 517 } 518 drmmode_output->props[j].index = i; 519 drmmode_output->props[j].mode_prop = drmmode_prop; 520 drmmode_output->props[j].value = mode_output->prop_values[i]; 521 drmmode_output->num_props++; 522 j++; 523 } 524 525 for (i = 0; i < drmmode_output->num_props; i++) { 526 drmmode_prop_ptr p = &drmmode_output->props[i]; 527 drmmode_prop = p->mode_prop; 528 529 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 530 INT32 qrange[2]; 531 INT32 value = p->value; 532 533 p->num_atoms = 1; 534 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 535 if (!p->atoms) 536 continue; 537 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 538 qrange[0] = drmmode_prop->values[0]; 539 qrange[1] = drmmode_prop->values[1]; 540 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 541 FALSE, TRUE, 542 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 543 2, qrange); 544 if (err != 0) { 545 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 546 "RRConfigureOutputProperty error, %d\n", err); 547 } 548 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 549 XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 550 if (err != 0) { 551 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 552 "RRChangeOutputProperty error, %d\n", err); 553 } 554 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 555 p->num_atoms = drmmode_prop->count_enums + 1; 556 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 557 if (!p->atoms) 558 continue; 559 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 560 for (j = 1; j <= drmmode_prop->count_enums; j++) { 561 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 562 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 563 } 564 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 565 FALSE, FALSE, 566 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 567 p->num_atoms - 1, (INT32 *)&p->atoms[1]); 568 if (err != 0) { 569 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 570 "RRConfigureOutputProperty error, %d\n", err); 571 } 572 for (j = 0; j < drmmode_prop->count_enums; j++) 573 if (drmmode_prop->enums[j].value == p->value) 574 break; 575 /* there's always a matching value */ 576 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 577 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 578 if (err != 0) { 579 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 580 "RRChangeOutputProperty error, %d\n", err); 581 } 582 } 583 } 584} 585 586static Bool 587drmmode_output_set_property(xf86OutputPtr output, Atom property, 588 RRPropertyValuePtr value) 589{ 590 drmmode_output_private_ptr drmmode_output = output->driver_private; 591 drmmode_ptr drmmode = drmmode_output->drmmode; 592 int i; 593 594 for (i = 0; i < drmmode_output->num_props; i++) { 595 drmmode_prop_ptr p = &drmmode_output->props[i]; 596 597 if (p->atoms[0] != property) 598 continue; 599 600 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 601 uint32_t val; 602 603 if (value->type != XA_INTEGER || value->format != 32 || 604 value->size != 1) 605 return FALSE; 606 val = *(uint32_t *)value->data; 607 608 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 609 p->mode_prop->prop_id, (uint64_t)val); 610 return TRUE; 611 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 612 Atom atom; 613 const char *name; 614 int j; 615 616 if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 617 return FALSE; 618 memcpy(&atom, value->data, 4); 619 if (!(name = NameForAtom(atom))) 620 return FALSE; 621 622 /* search for matching name string, then set its value down */ 623 for (j = 0; j < p->mode_prop->count_enums; j++) { 624 if (!strcmp(p->mode_prop->enums[j].name, name)) { 625 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 626 p->mode_prop->prop_id, p->mode_prop->enums[j].value); 627 return TRUE; 628 } 629 } 630 } 631 } 632 633 return TRUE; 634} 635 636static Bool 637drmmode_output_get_property(xf86OutputPtr output, Atom property) 638{ 639 drmmode_output_private_ptr drmmode_output = output->driver_private; 640 drmmode_ptr drmmode = drmmode_output->drmmode; 641 uint32_t value; 642 int err, i; 643 644 if (output->scrn->vtSema) { 645 drmModeFreeConnector(drmmode_output->mode_output); 646 drmmode_output->mode_output = 647 drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 648 } 649 650 if (!drmmode_output->mode_output) 651 return FALSE; 652 653 for (i = 0; i < drmmode_output->num_props; i++) { 654 drmmode_prop_ptr p = &drmmode_output->props[i]; 655 if (p->atoms[0] != property) 656 continue; 657 658 value = drmmode_output->mode_output->prop_values[p->index]; 659 660 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 661 err = RRChangeOutputProperty(output->randr_output, 662 property, XA_INTEGER, 32, 663 PropModeReplace, 1, &value, 664 FALSE, FALSE); 665 666 return !err; 667 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 668 int j; 669 670 /* search for matching name string, then set its value down */ 671 for (j = 0; j < p->mode_prop->count_enums; j++) { 672 if (p->mode_prop->enums[j].value == value) 673 break; 674 } 675 676 err = RRChangeOutputProperty(output->randr_output, property, 677 XA_ATOM, 32, PropModeReplace, 1, 678 &p->atoms[j+1], FALSE, FALSE); 679 680 return !err; 681 } 682 } 683 684 return FALSE; 685} 686 687static const xf86OutputFuncsRec drmmode_output_funcs = { 688 .dpms = drmmode_output_dpms, 689 .create_resources = drmmode_output_create_resources, 690#ifdef RANDR_12_INTERFACE 691 .set_property = drmmode_output_set_property, 692 .get_property = drmmode_output_get_property, 693#endif 694#if 0 695 696 .save = drmmode_crt_save, 697 .restore = drmmode_crt_restore, 698 .mode_fixup = drmmode_crt_mode_fixup, 699 .prepare = drmmode_output_prepare, 700 .mode_set = drmmode_crt_mode_set, 701 .commit = drmmode_output_commit, 702#endif 703 .detect = drmmode_output_detect, 704 .mode_valid = drmmode_output_mode_valid, 705 706 .get_modes = drmmode_output_get_modes, 707 .destroy = drmmode_output_destroy 708}; 709 710static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 711 SubPixelHorizontalRGB, 712 SubPixelHorizontalBGR, 713 SubPixelVerticalRGB, 714 SubPixelVerticalBGR, 715 SubPixelNone }; 716 717const char *output_names[] = { 718 "None", 719 "VGA", 720 "DVI-I", 721 "DVI-D", 722 "DVI-A", 723 "Composite", 724 "SVIDEO", 725 "LVDS", 726 "Component", 727 "DIN", 728 "DP", 729 "HDMI", 730 "HDMI-B", 731 "TV", 732 "eDP", 733 "Virtual", 734 "DSI", 735 "DPI", 736}; 737 738static void 739drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 740{ 741 xf86OutputPtr output; 742 drmModeConnectorPtr koutput; 743 drmModeEncoderPtr *kencoders = NULL; 744 drmmode_output_private_ptr drmmode_output; 745 drmModePropertyPtr props; 746 char name[32]; 747 int i; 748 749 koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); 750 if (!koutput) 751 return; 752 753 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 754 if (!kencoders) { 755 goto out_free_encoders; 756 } 757 758 for (i = 0; i < koutput->count_encoders; i++) { 759 kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 760 if (!kencoders[i]) { 761 goto out_free_encoders; 762 } 763 } 764 765 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id); 766 767 768 output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 769 if (!output) { 770 goto out_free_encoders; 771 } 772 773 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 774 if (!drmmode_output) { 775 xf86OutputDestroy(output); 776 goto out_free_encoders; 777 } 778 779 drmmode_output->output_id = drmmode->mode_res->connectors[num]; 780 drmmode_output->mode_output = koutput; 781 drmmode_output->mode_encoders = kencoders; 782 drmmode_output->drmmode = drmmode; 783 output->mm_width = koutput->mmWidth; 784 output->mm_height = koutput->mmHeight; 785 786 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 787 output->interlaceAllowed = TRUE; 788 output->doubleScanAllowed = TRUE; 789 output->driver_private = drmmode_output; 790 791 output->possible_crtcs = 0xffffffff; 792 for (i = 0; i < koutput->count_encoders; i++) { 793 output->possible_crtcs &= kencoders[i]->possible_crtcs; 794 } 795 /* work out the possible clones later */ 796 output->possible_clones = 0; 797 798 for (i = 0; i < koutput->count_props; i++) { 799 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 800 if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 801 if (!strcmp(props->name, "DPMS")) { 802 drmmode_output->dpms_enum_id = koutput->props[i]; 803 drmModeFreeProperty(props); 804 break; 805 } 806 drmModeFreeProperty(props); 807 } 808 } 809 810 return; 811out_free_encoders: 812 if (kencoders){ 813 for (i = 0; i < koutput->count_encoders; i++) 814 drmModeFreeEncoder(kencoders[i]); 815 free(kencoders); 816 } 817 drmModeFreeConnector(koutput); 818 819} 820 821static Bool 822drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 823{ 824 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 825 drmmode_crtc_private_ptr 826 drmmode_crtc = xf86_config->crtc[0]->driver_private; 827 drmmode_ptr drmmode = drmmode_crtc->drmmode; 828 struct qxl_bo *old_front = NULL; 829 struct qxl_bo *front_bo; 830 qxl_screen_t *qxl = scrn->driverPrivate; 831 int cpp = (scrn->bitsPerPixel + 7) / 8; 832 int32_t pitch, old_pitch; 833 int ret, i; 834 uint32_t old_width, old_height, old_fb_id; 835 if (scrn->virtualX == width && scrn->virtualY == height) 836 return TRUE; 837 838 xf86DrvMsg(scrn->scrnIndex, X_INFO, 839 "Allocate new frame buffer %dx%d stride\n", 840 width, height); 841 842 front_bo = qxl->primary->bo; 843 844 pitch = width * cpp; 845 old_width = scrn->virtualX; 846 old_height = scrn->virtualY; 847 old_pitch = scrn->displayWidth; 848 old_fb_id = drmmode->fb_id; 849 old_front = front_bo; 850 851 scrn->virtualX = width; 852 scrn->virtualY = height; 853 scrn->displayWidth = pitch / cpp; 854 855 qxl->primary->bo = qxl->bo_funcs->create_primary(qxl, width, height, pitch, SPICE_SURFACE_FMT_32_xRGB); 856 if (!qxl->primary->bo) 857 goto fail; 858 859 ret = drmModeAddFB(drmmode->fd, 860 width, height, 861 scrn->depth, scrn->bitsPerPixel, 862 pitch, 863 qxl_kms_bo_get_handle(qxl->primary->bo), 864 &drmmode->fb_id); 865 if (ret) 866 goto fail; 867 868 for (i = 0; i < xf86_config->num_crtc; i++) { 869 xf86CrtcPtr crtc = xf86_config->crtc[i]; 870 if (!crtc->enabled) 871 continue; 872 if (!drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 873 crtc->x, crtc->y)) 874 goto fail; 875 } 876 877 { 878 void *dev_ptr = qxl->bo_funcs->bo_map(qxl->primary->bo); 879 uint32_t *dev_addr; 880 int format = scrn->bitsPerPixel == 16 ? PIXMAN_x1r5g5b5 : PIXMAN_x8r8g8b8; 881 dev_addr = dev_ptr; 882 pixman_image_unref(qxl->primary->dev_image); 883 pixman_image_unref (qxl->primary->host_image); 884 885 qxl->primary->dev_image = pixman_image_create_bits (format, 886 width, 887 height, 888 (uint32_t *)dev_addr, pitch); 889 890 qxl->primary->host_image = pixman_image_create_bits (format, 891 width, 892 height, 893 NULL, pitch); 894 } 895 896 /* fixup the surfaces */ 897 898 if (old_fb_id) 899 drmModeRmFB(drmmode->fd, old_fb_id); 900 if (old_front) 901 qxl->bo_funcs->bo_decref(qxl, old_front); 902 903 return TRUE; 904fail: 905 qxl->primary->bo = old_front; 906 scrn->virtualX = old_width; 907 scrn->virtualY = old_height; 908 scrn->displayWidth = old_pitch; 909 drmmode->fb_id = old_fb_id; 910 return FALSE; 911} 912 913 914static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 915 drmmode_xf86crtc_resize, 916}; 917 918Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 919{ 920 int i; 921 922 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 923 924 drmmode->scrn = pScrn; 925 drmmode->cpp = cpp; 926 drmmode->mode_res = drmModeGetResources(drmmode->fd); 927 if (!drmmode->mode_res) 928 return FALSE; 929 930 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); 931 for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 932 drmmode_crtc_init(pScrn, drmmode, i); 933 934 for (i = 0; i < drmmode->mode_res->count_connectors; i++) 935 drmmode_output_init(pScrn, drmmode, i); 936 937#if XF86_CRTC_VERSION >= 5 938 xf86ProviderSetup(pScrn, NULL, "qxl"); 939#endif 940 xf86InitialConfiguration(pScrn, TRUE); 941 942 return TRUE; 943} 944 945#ifdef HAVE_LIBUDEV 946static void 947drmmode_handle_uevents(int fd, void *closure) 948{ 949 drmmode_ptr drmmode = closure; 950 ScrnInfoPtr scrn = drmmode->scrn; 951 struct udev_device *dev; 952 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 953 if (!dev) 954 return; 955 956 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 957 udev_device_unref(dev); 958} 959#endif 960 961void qxl_drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 962{ 963#ifdef HAVE_LIBUDEV 964 struct udev *u; 965 struct udev_monitor *mon; 966 967 u = udev_new(); 968 if (!u) 969 return; 970 mon = udev_monitor_new_from_netlink(u, "udev"); 971 if (!mon) { 972 udev_unref(u); 973 return; 974 } 975 976 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 977 "drm", 978 "drm_minor") < 0 || 979 udev_monitor_enable_receiving(mon) < 0) { 980 udev_monitor_unref(mon); 981 udev_unref(u); 982 return; 983 } 984 985 drmmode->uevent_handler = 986 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 987 drmmode_handle_uevents, 988 drmmode); 989 990 drmmode->uevent_monitor = mon; 991#endif 992} 993 994void qxl_drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 995{ 996#ifdef HAVE_LIBUDEV 997 if (drmmode->uevent_handler) { 998 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 999 xf86RemoveGeneralHandler(drmmode->uevent_handler); 1000 1001 udev_monitor_unref(drmmode->uevent_monitor); 1002 udev_unref(u); 1003 } 1004#endif 1005} 1006 1007#endif 1008