Home | History | Annotate | Line # | Download | only in src
      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 (at) 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 
     45 static void drmmode_show_cursor (xf86CrtcPtr crtc);
     46 
     47 static void
     48 drmmode_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 
     79 static void
     80 drmmode_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 
    107 static void
    108 drmmode_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 
    124 static Bool
    125 drmmode_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 
    236 done:
    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 
    255 static void
    256 drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
    257 {
    258 
    259 }
    260 
    261 static void
    262 drmmode_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 
    270 static void
    271 drmmode_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 
    291 static void
    292 drmmode_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 
    307 static void
    308 drmmode_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 
    316 static void
    317 drmmode_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 }
    326 static 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 
    339 static void
    340 drmmode_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 
    372 static xf86OutputStatus
    373 drmmode_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 
    398 static Bool
    399 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
    400 {
    401 	return MODE_OK;
    402 }
    403 
    404 static DisplayModePtr
    405 drmmode_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 
    447 static void
    448 drmmode_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 
    469 static void
    470 drmmode_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 
    482 static Bool
    483 drmmode_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 
    498 static void
    499 drmmode_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 
    586 static Bool
    587 drmmode_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 
    636 static Bool
    637 drmmode_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 
    687 static 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 
    710 static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
    711 				      SubPixelHorizontalRGB,
    712 				      SubPixelHorizontalBGR,
    713 				      SubPixelVerticalRGB,
    714 				      SubPixelVerticalBGR,
    715 				      SubPixelNone };
    716 
    717 const 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 
    738 static void
    739 drmmode_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;
    811 out_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 
    821 static Bool
    822 drmmode_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;
    904 fail:
    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 
    914 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
    915 	drmmode_xf86crtc_resize,
    916 };
    917 
    918 Bool 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
    946 static void
    947 drmmode_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 
    961 void 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 
    994 void 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