Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2007 Red Hat, Inc.
      3  * Copyright  2008 Maarten Maathuis
      4  *
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Authors:
     26  *    Dave Airlie <airlied (at) redhat.com>
     27  *
     28  */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 #include "config.h"
     32 #endif
     33 
     34 #include "xorg-config.h"
     35 #include "xorgVersion.h"
     36 #include "Xdefs.h"
     37 #include "X11/Xdefs.h"
     38 
     39 #include "nv_include.h"
     40 #include "xf86drmMode.h"
     41 #include "X11/Xatom.h"
     42 
     43 #include <sys/ioctl.h>
     44 #ifdef HAVE_LIBUDEV
     45 #include "libudev.h"
     46 #endif
     47 
     48 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
     49 typedef struct {
     50     int fd;
     51     uint32_t fb_id;
     52     int cpp;
     53     drmEventContext event_context;
     54 #ifdef HAVE_LIBUDEV
     55     struct udev_monitor *uevent_monitor;
     56 #endif
     57 } drmmode_rec, *drmmode_ptr;
     58 
     59 typedef struct {
     60     drmmode_ptr drmmode;
     61     drmModeCrtcPtr mode_crtc;
     62     int hw_crtc_index;
     63     struct nouveau_bo *cursor;
     64     struct nouveau_bo *rotate_bo;
     65     int rotate_pitch;
     66     PixmapPtr rotate_pixmap;
     67     uint32_t rotate_fb_id;
     68     Bool cursor_visible;
     69     int scanout_pixmap_x;
     70     int dpms_mode;
     71 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
     72 
     73 typedef struct {
     74 	drmModePropertyPtr mode_prop;
     75 	int index; /* Index within the kernel-side property arrays for
     76 		    * this connector. */
     77 	int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
     78 			* num_atoms == num_enums + 1 */
     79 	Atom *atoms;
     80 } drmmode_prop_rec, *drmmode_prop_ptr;
     81 
     82 typedef struct {
     83     drmmode_ptr drmmode;
     84     int output_id;
     85     drmModeConnectorPtr mode_output;
     86     drmModeEncoderPtr mode_encoder;
     87     drmModePropertyBlobPtr edid_blob;
     88     drmModePropertyBlobPtr tile_blob;
     89     int num_props;
     90     drmmode_prop_ptr props;
     91 } drmmode_output_private_rec, *drmmode_output_private_ptr;
     92 
     93 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
     94 
     95 static drmmode_ptr
     96 drmmode_from_scrn(ScrnInfoPtr scrn)
     97 {
     98 	if (scrn) {
     99 		xf86CrtcConfigPtr conf = XF86_CRTC_CONFIG_PTR(scrn);
    100 		drmmode_crtc_private_ptr crtc = conf->crtc[0]->driver_private;
    101 
    102 		return crtc->drmmode;
    103 	}
    104 
    105 	return NULL;
    106 }
    107 
    108 static inline struct nouveau_pixmap *
    109 drmmode_pixmap(PixmapPtr ppix)
    110 {
    111 	return nouveau_pixmap(ppix);
    112 }
    113 
    114 int
    115 drmmode_crtc(xf86CrtcPtr crtc)
    116 {
    117 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    118 	return drmmode_crtc->mode_crtc->crtc_id;
    119 }
    120 
    121 Bool
    122 xf86_crtc_on(xf86CrtcPtr crtc)
    123 {
    124     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    125 
    126     return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn;
    127 }
    128 
    129 int
    130 drmmode_head(xf86CrtcPtr crtc)
    131 {
    132 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    133 	return drmmode_crtc->hw_crtc_index;
    134 }
    135 
    136 void
    137 drmmode_swap(ScrnInfoPtr scrn, uint32_t next, uint32_t *prev)
    138 {
    139 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    140 	*prev = drmmode->fb_id;
    141 	drmmode->fb_id = next;
    142 }
    143 
    144 struct drmmode_event {
    145 	struct xorg_list head;
    146 	drmmode_ptr drmmode;
    147 	uint64_t name;
    148 	void (*func)(void *, uint64_t, uint64_t, uint32_t);
    149 };
    150 
    151 static struct xorg_list
    152 drmmode_events = {
    153 	.next = &drmmode_events,
    154 	.prev = &drmmode_events,
    155 };
    156 
    157 static bool warned = false;
    158 
    159 static void
    160 drmmode_event_handler(int fd, unsigned int frame, unsigned int tv_sec,
    161 		      unsigned int tv_usec, void *event_data)
    162 {
    163 	const uint64_t ust = (uint64_t)tv_sec * 1000000 + tv_usec;
    164 	struct drmmode_event *e = event_data;
    165 
    166 	int counter = 0;
    167 
    168 	xorg_list_for_each_entry(e, &drmmode_events, head) {
    169 		counter++;
    170 		if (e == event_data) {
    171 			xorg_list_del(&e->head);
    172 			e->func((void *)(e + 1), e->name, ust, frame);
    173 			free(e);
    174 			break;
    175 		}
    176 	}
    177 
    178 	if (counter > 100 && !warned) {
    179 		xf86DrvMsg(0, X_WARNING,
    180 			   "Event handler iterated %d times\n", counter);
    181 		warned = true;
    182 	}
    183 }
    184 
    185 void
    186 drmmode_event_abort(ScrnInfoPtr scrn, uint64_t name, bool pending)
    187 {
    188 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    189 	struct drmmode_event *e, *t;
    190 
    191 	xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) {
    192 		if (e->drmmode == drmmode && e->name == name) {
    193 			xorg_list_del(&e->head);
    194 			if (!pending)
    195 				free(e);
    196 			break;
    197 		}
    198 	}
    199 }
    200 
    201 void *
    202 drmmode_event_queue(ScrnInfoPtr scrn, uint64_t name, unsigned size,
    203 		    void (*func)(void *, uint64_t, uint64_t, uint32_t),
    204 		    void **event_data)
    205 {
    206 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    207 	struct drmmode_event *e;
    208 
    209 	e = *event_data = calloc(1, sizeof(*e) + size);
    210 	if (e) {
    211 		e->drmmode = drmmode;
    212 		e->name = name;
    213 		e->func = func;
    214 		xorg_list_append(&e->head, &drmmode_events);
    215 		return (void *)(e + 1);
    216 	}
    217 
    218 	return NULL;
    219 }
    220 
    221 int
    222 drmmode_event_flush(ScrnInfoPtr scrn)
    223 {
    224 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    225 	return drmHandleEvent(drmmode->fd, &drmmode->event_context);
    226 }
    227 
    228 void
    229 drmmode_event_fini(ScrnInfoPtr scrn)
    230 {
    231 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    232 	struct drmmode_event *e, *t;
    233 
    234 	xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) {
    235 		if (e->drmmode == drmmode) {
    236 			xorg_list_del(&e->head);
    237 			free(e);
    238 		}
    239 	}
    240 }
    241 
    242 void
    243 drmmode_event_init(ScrnInfoPtr scrn)
    244 {
    245 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
    246 	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
    247 	drmmode->event_context.vblank_handler = drmmode_event_handler;
    248 	drmmode->event_context.page_flip_handler = drmmode_event_handler;
    249 }
    250 
    251 static PixmapPtr
    252 drmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth,
    253 		    int bpp, int pitch, struct nouveau_bo *bo, void *data)
    254 {
    255 	NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen));
    256 	PixmapPtr ppix;
    257 
    258 	if (pNv->AccelMethod > NONE)
    259 		data = NULL;
    260 
    261 	ppix = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0);
    262 	if (!ppix)
    263 		return NULL;
    264 
    265 	pScreen->ModifyPixmapHeader(ppix, width, height, depth, bpp,
    266 				    pitch, data);
    267 	if (pNv->AccelMethod > NONE)
    268 		nouveau_bo_ref(bo, &drmmode_pixmap(ppix)->bo);
    269 
    270 	return ppix;
    271 }
    272 
    273 static void
    274 drmmode_ConvertFromKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode,
    275 			 DisplayModePtr	mode)
    276 {
    277 	memset(mode, 0, sizeof(DisplayModeRec));
    278 	mode->status = MODE_OK;
    279 
    280 	mode->Clock = kmode->clock;
    281 
    282 	mode->HDisplay = kmode->hdisplay;
    283 	mode->HSyncStart = kmode->hsync_start;
    284 	mode->HSyncEnd = kmode->hsync_end;
    285 	mode->HTotal = kmode->htotal;
    286 	mode->HSkew = kmode->hskew;
    287 
    288 	mode->VDisplay = kmode->vdisplay;
    289 	mode->VSyncStart = kmode->vsync_start;
    290 	mode->VSyncEnd = kmode->vsync_end;
    291 	mode->VTotal = kmode->vtotal;
    292 	mode->VScan = kmode->vscan;
    293 
    294 	mode->Flags = kmode->flags; //& FLAG_BITS;
    295 	mode->name = strdup(kmode->name);
    296 
    297 	if (kmode->type & DRM_MODE_TYPE_DRIVER)
    298 		mode->type = M_T_DRIVER;
    299 	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
    300 		mode->type |= M_T_PREFERRED;
    301 	xf86SetModeCrtc (mode, scrn->adjustFlags);
    302 }
    303 
    304 static void
    305 drmmode_ConvertToKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode,
    306 		       DisplayModePtr mode)
    307 {
    308 	memset(kmode, 0, sizeof(*kmode));
    309 
    310 	kmode->clock = mode->Clock;
    311 	kmode->hdisplay = mode->HDisplay;
    312 	kmode->hsync_start = mode->HSyncStart;
    313 	kmode->hsync_end = mode->HSyncEnd;
    314 	kmode->htotal = mode->HTotal;
    315 	kmode->hskew = mode->HSkew;
    316 
    317 	kmode->vdisplay = mode->VDisplay;
    318 	kmode->vsync_start = mode->VSyncStart;
    319 	kmode->vsync_end = mode->VSyncEnd;
    320 	kmode->vtotal = mode->VTotal;
    321 	kmode->vscan = mode->VScan;
    322 
    323 	kmode->flags = mode->Flags; //& FLAG_BITS;
    324 	if (mode->name)
    325 		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
    326 	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
    327 
    328 }
    329 
    330 static void
    331 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
    332 {
    333 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    334 	drmmode_crtc->dpms_mode = mode;
    335 }
    336 
    337 void
    338 drmmode_fbcon_copy(ScreenPtr pScreen)
    339 {
    340 	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    341 	NVPtr pNv = NVPTR(pScrn);
    342 	if (nouveau_bo_map(pNv->scanout, NOUVEAU_BO_WR, pNv->client))
    343 		return;
    344 	memset(pNv->scanout->map, 0x00, pNv->scanout->size);
    345 }
    346 
    347 static Bool
    348 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
    349 		       Rotation rotation, int x, int y)
    350 {
    351 	ScrnInfoPtr pScrn = crtc->scrn;
    352 	NVPtr pNv = NVPTR(pScrn);
    353 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    354 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    355 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    356 	uint32_t *output_ids;
    357 	int output_count = 0;
    358 	int ret = TRUE;
    359 	int i;
    360 	int fb_id;
    361 	drmModeModeInfo kmode;
    362 
    363 	if (drmmode->fb_id == 0) {
    364 		unsigned int pitch =
    365 			pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
    366 
    367 		ret = drmModeAddFB(drmmode->fd,
    368 				   pScrn->virtualX, pScrn->virtualY,
    369 				   pScrn->depth, pScrn->bitsPerPixel,
    370 				   pitch, pNv->scanout->handle,
    371 				   &drmmode->fb_id);
    372 		if (ret < 0) {
    373 			ErrorF("failed to add fb\n");
    374 			return FALSE;
    375 		}
    376 	}
    377 
    378 	if (!xf86CrtcRotate(crtc))
    379 		return FALSE;
    380 
    381 	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
    382 	if (!output_ids)
    383 		return FALSE;
    384 
    385 	for (i = 0; i < xf86_config->num_output; i++) {
    386 		xf86OutputPtr output = xf86_config->output[i];
    387 		drmmode_output_private_ptr drmmode_output;
    388 
    389 		if (output->crtc != crtc)
    390 			continue;
    391 
    392 		drmmode_output = output->driver_private;
    393 		if (drmmode_output->output_id == -1)
    394 			continue;
    395 		output_ids[output_count] =
    396 			drmmode_output->mode_output->connector_id;
    397 		output_count++;
    398 	}
    399 
    400 	drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
    401 
    402 	fb_id = drmmode->fb_id;
    403 #ifdef NOUVEAU_PIXMAP_SHARING
    404 	if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
    405 		x = drmmode_crtc->scanout_pixmap_x;
    406 		y = 0;
    407 	} else
    408 #endif
    409 	if (drmmode_crtc->rotate_fb_id) {
    410 		fb_id = drmmode_crtc->rotate_fb_id;
    411 		x = 0;
    412 		y = 0;
    413 	}
    414 
    415 	ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    416 			     fb_id, x, y, output_ids, output_count, &kmode);
    417 	free(output_ids);
    418 
    419 	if (ret) {
    420 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    421 			   "failed to set mode: %s\n", strerror(-ret));
    422 		return FALSE;
    423 	}
    424 
    425 	/* Work around some xserver stupidity */
    426 	for (i = 0; i < xf86_config->num_output; i++) {
    427 		xf86OutputPtr output = xf86_config->output[i];
    428 
    429 		if (output->crtc != crtc)
    430 			continue;
    431 
    432 		drmmode_output_dpms(output, DPMSModeOn);
    433 	}
    434 
    435 	crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
    436 			       crtc->gamma_blue, crtc->gamma_size);
    437 
    438 #ifdef HAVE_XF86_CURSOR_RESET_CURSOR
    439 	xf86CursorResetCursor(crtc->scrn->pScreen);
    440 #else
    441 	xf86_reload_cursors(crtc->scrn->pScreen);
    442 #endif
    443 
    444 	return TRUE;
    445 }
    446 
    447 static void
    448 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
    449 {
    450 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    451 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    452 
    453 	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
    454 }
    455 
    456 static void
    457 convert_cursor(CARD32 *dst, CARD32 *src, int dw, int sw)
    458 {
    459 	int i, j;
    460 
    461 	for (j = 0;  j < sw; j++) {
    462 		for (i = 0; i < sw; i++) {
    463 			dst[j * dw + i] = src[j * sw + i];
    464 		}
    465 	}
    466 }
    467 
    468 static void
    469 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
    470 {
    471 	NVPtr pNv = NVPTR(crtc->scrn);
    472 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    473 	struct nouveau_bo *cursor = drmmode_crtc->cursor;
    474 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    475 
    476 	nouveau_bo_map(cursor, NOUVEAU_BO_WR, pNv->client);
    477 	convert_cursor(cursor->map, image, 64, nv_cursor_width(pNv));
    478 
    479 	if (drmmode_crtc->cursor_visible) {
    480 		drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    481 				 cursor->handle, 64, 64);
    482 	}
    483 }
    484 
    485 static void
    486 drmmode_hide_cursor (xf86CrtcPtr crtc)
    487 {
    488 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    489 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    490 
    491 	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    492 			 0, 64, 64);
    493 	drmmode_crtc->cursor_visible = FALSE;
    494 }
    495 
    496 static void
    497 drmmode_show_cursor (xf86CrtcPtr crtc)
    498 {
    499 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    500 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    501 
    502 	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    503 			 drmmode_crtc->cursor->handle, 64, 64);
    504 	drmmode_crtc->cursor_visible = TRUE;
    505 }
    506 
    507 static void *
    508 drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
    509 {
    510 	ScrnInfoPtr scrn = crtc->scrn;
    511 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    512 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    513 	void *virtual;
    514 	int ret;
    515 
    516 	ret = nouveau_allocate_surface(scrn, width, height,
    517 				       scrn->bitsPerPixel,
    518 				       NOUVEAU_CREATE_PIXMAP_SCANOUT,
    519 				       &drmmode_crtc->rotate_pitch,
    520 				       &drmmode_crtc->rotate_bo);
    521 	if (!ret) {
    522 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    523 			   "Couldn't allocate shadow memory for rotated CRTC\n");
    524 		return NULL;
    525 	}
    526 
    527 	ret = nouveau_bo_map(drmmode_crtc->rotate_bo, NOUVEAU_BO_RDWR,
    528 			     NVPTR(scrn)->client);
    529 	if (ret) {
    530 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    531 			   "Couldn't get virtual address of shadow scanout\n");
    532 		nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo);
    533 		return NULL;
    534 	}
    535 	virtual = drmmode_crtc->rotate_bo->map;
    536 
    537 	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
    538 			   crtc->scrn->bitsPerPixel, drmmode_crtc->rotate_pitch,
    539 			   drmmode_crtc->rotate_bo->handle,
    540 			   &drmmode_crtc->rotate_fb_id);
    541 	if (ret) {
    542 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    543 			   "Error adding FB for shadow scanout: %s\n",
    544 			   strerror(-ret));
    545 		nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo);
    546 		return NULL;
    547 	}
    548 
    549 	return virtual;
    550 }
    551 
    552 static PixmapPtr
    553 drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
    554 {
    555 	ScrnInfoPtr pScrn = crtc->scrn;
    556 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    557 	PixmapPtr rotate_pixmap;
    558 
    559 	if (!data)
    560 		data = drmmode_crtc_shadow_allocate (crtc, width, height);
    561 
    562 	rotate_pixmap = drmmode_pixmap_wrap(pScrn->pScreen, width, height,
    563 					    pScrn->depth, pScrn->bitsPerPixel,
    564 					    drmmode_crtc->rotate_pitch,
    565 					    drmmode_crtc->rotate_bo, data);
    566 
    567 	drmmode_crtc->rotate_pixmap = rotate_pixmap;
    568 	return drmmode_crtc->rotate_pixmap;
    569 }
    570 
    571 static void
    572 drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
    573 {
    574 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    575 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    576 
    577 	if (rotate_pixmap)
    578 		FreeScratchPixmapHeader(rotate_pixmap);
    579 
    580 	if (data) {
    581 		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
    582 		drmmode_crtc->rotate_fb_id = 0;
    583 		nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo);
    584 		drmmode_crtc->rotate_pixmap = NULL;
    585 	}
    586 }
    587 
    588 static void
    589 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
    590 		  int size)
    591 {
    592 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    593 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    594 	int ret;
    595 
    596 	ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    597 				  size, red, green, blue);
    598 	if (ret != 0) {
    599 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
    600 			   "failed to set gamma with %d entries: %s\n",
    601 			   size, strerror(-ret));
    602 	}
    603 }
    604 
    605 #ifdef NOUVEAU_PIXMAP_SHARING
    606 static Bool
    607 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
    608 {
    609 	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
    610 	PixmapPtr screenpix = screen->GetScreenPixmap(screen);
    611 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    612 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    613 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
    614 	int c, total_width = 0, max_height = 0, this_x = 0;
    615 	if (!ppix) {
    616 		if (crtc->randr_crtc->scanout_pixmap) {
    617 #ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
    618 			PixmapStopDirtyTracking(&crtc->randr_crtc->scanout_pixmap->drawable, screenpix);
    619 #else
    620 			PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix);
    621 #endif
    622 			if (drmmode && drmmode->fb_id) {
    623 				drmModeRmFB(drmmode->fd, drmmode->fb_id);
    624 				drmmode->fb_id = 0;
    625 			}
    626 		}
    627 		drmmode_crtc->scanout_pixmap_x = 0;
    628 		return TRUE;
    629 	}
    630 
    631 	/* iterate over all the attached crtcs -
    632 	   work out bounding box */
    633 	for (c = 0; c < xf86_config->num_crtc; c++) {
    634 		xf86CrtcPtr iter = xf86_config->crtc[c];
    635 		if (!iter->enabled && iter != crtc)
    636 			continue;
    637 		if (iter == crtc) {
    638 			this_x = total_width;
    639 			total_width += ppix->drawable.width;
    640 			if (max_height < ppix->drawable.height)
    641 				max_height = ppix->drawable.height;
    642 		} else {
    643 			total_width += iter->mode.HDisplay;
    644 			if (max_height < iter->mode.VDisplay)
    645 				max_height = iter->mode.VDisplay;
    646 		}
    647 	}
    648 
    649 	if (total_width != screenpix->drawable.width ||
    650 	    max_height != screenpix->drawable.height) {
    651 		Bool ret;
    652 		ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height);
    653 		if (ret == FALSE)
    654 			return FALSE;
    655 
    656 		screenpix = screen->GetScreenPixmap(screen);
    657 		screen->width = screenpix->drawable.width = total_width;
    658 		screen->height = screenpix->drawable.height = max_height;
    659 	}
    660 	drmmode_crtc->scanout_pixmap_x = this_x;
    661 
    662 #ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
    663 	PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0, RR_Rotate_0);
    664 #else
    665 	PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0);
    666 #endif
    667 	return TRUE;
    668 }
    669 #endif
    670 
    671 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
    672 	.dpms = drmmode_crtc_dpms,
    673 	.set_mode_major = drmmode_set_mode_major,
    674 	.set_cursor_position = drmmode_set_cursor_position,
    675 	.show_cursor = drmmode_show_cursor,
    676 	.hide_cursor = drmmode_hide_cursor,
    677 	.load_cursor_argb = drmmode_load_cursor_argb,
    678 	.shadow_create = drmmode_crtc_shadow_create,
    679 	.shadow_allocate = drmmode_crtc_shadow_allocate,
    680 	.shadow_destroy = drmmode_crtc_shadow_destroy,
    681 	.gamma_set = drmmode_gamma_set,
    682 
    683 #ifdef NOUVEAU_PIXMAP_SHARING
    684 	.set_scanout_pixmap = drmmode_set_scanout_pixmap,
    685 #endif
    686 };
    687 
    688 
    689 static unsigned int
    690 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
    691 {
    692 	NVPtr pNv = NVPTR(pScrn);
    693 	NVEntPtr pNVEnt = NVEntPriv(pScrn);
    694 	xf86CrtcPtr crtc;
    695 	drmmode_crtc_private_ptr drmmode_crtc;
    696 	int ret;
    697 
    698 	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
    699 	if (crtc == NULL)
    700 		return 0;
    701 
    702 	drmmode_crtc = XNFcallocarray(sizeof(drmmode_crtc_private_rec), 1);
    703 	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
    704 						 mode_res->crtcs[num]);
    705 	drmmode_crtc->drmmode = drmmode;
    706 	drmmode_crtc->hw_crtc_index = num;
    707 
    708 	ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
    709 			     64*64*4, NULL, &drmmode_crtc->cursor);
    710 	assert(ret == 0);
    711 
    712 	crtc->driver_private = drmmode_crtc;
    713 
    714 	/* Mark num'th crtc as in use on this device. */
    715 	pNVEnt->assigned_crtcs |= (1 << num);
    716 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
    717 		   "Allocated crtc nr. %d to this screen.\n", num);
    718 
    719 	return 1;
    720 }
    721 
    722 static xf86OutputStatus
    723 drmmode_output_detect(xf86OutputPtr output)
    724 {
    725 	/* go to the hw and retrieve a new output struct */
    726 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    727 	drmmode_ptr drmmode = drmmode_output->drmmode;
    728 	xf86OutputStatus status;
    729 
    730 	if (drmmode_output->output_id == -1)
    731 		return XF86OutputStatusDisconnected;
    732 
    733 	drmModeFreeConnector(drmmode_output->mode_output);
    734 
    735 	drmmode_output->mode_output =
    736 		drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
    737 
    738 	if (!drmmode_output->mode_output) {
    739 		drmmode_output->output_id = -1;
    740 		return XF86OutputStatusDisconnected;
    741 	}
    742 
    743 	switch (drmmode_output->mode_output->connection) {
    744 	case DRM_MODE_CONNECTED:
    745 		status = XF86OutputStatusConnected;
    746 		break;
    747 	case DRM_MODE_DISCONNECTED:
    748 		status = XF86OutputStatusDisconnected;
    749 		break;
    750 	default:
    751 	case DRM_MODE_UNKNOWNCONNECTION:
    752 		status = XF86OutputStatusUnknown;
    753 		break;
    754 	}
    755 	return status;
    756 }
    757 
    758 static Bool
    759 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
    760 {
    761 	if (mode->type & M_T_DEFAULT)
    762 		/* Default modes are harmful here. */
    763 		return MODE_BAD;
    764 
    765 	return MODE_OK;
    766 }
    767 
    768 static int
    769 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
    770 		     int type, const char *name)
    771 {
    772 	int idx = -1;
    773 
    774 	for (int i = 0; i < koutput->count_props; i++) {
    775 		drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
    776 
    777 		if (!prop)
    778 			continue;
    779 
    780 		if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
    781 			idx = i;
    782 
    783 		drmModeFreeProperty(prop);
    784 
    785 		if (idx > -1)
    786 			break;
    787 	}
    788 
    789 	return idx;
    790 }
    791 
    792 static drmModePropertyBlobPtr
    793 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
    794 {
    795 	drmModePropertyBlobPtr blob = NULL;
    796 	int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
    797 
    798 	if (idx > -1)
    799 		blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
    800 
    801 	return blob;
    802 }
    803 
    804 static void
    805 drmmode_output_attach_tile(xf86OutputPtr output)
    806 {
    807 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    808 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    809 	drmmode_ptr drmmode = drmmode_output->drmmode;
    810 	struct xf86CrtcTileInfo tile_info, *set = NULL;
    811 
    812 	if (!koutput) {
    813 		xf86OutputSetTile(output, NULL);
    814 		return;
    815 	}
    816 
    817 	drmModeFreePropertyBlob(drmmode_output->tile_blob);
    818 
    819 	/* look for a TILE property */
    820 	drmmode_output->tile_blob =
    821 		koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
    822 
    823 	if (drmmode_output->tile_blob) {
    824 		if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
    825 			set = &tile_info;
    826 	}
    827 	xf86OutputSetTile(output, set);
    828 }
    829 
    830 
    831 static DisplayModePtr
    832 drmmode_output_get_modes(xf86OutputPtr output)
    833 {
    834 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    835 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    836 	drmmode_ptr drmmode = drmmode_output->drmmode;
    837 	int i;
    838 	DisplayModePtr Modes = NULL, Mode;
    839 	xf86MonPtr ddc_mon = NULL;
    840 
    841 	if (!koutput)
    842 		return NULL;
    843 
    844 	/* look for an EDID property */
    845 	drmmode_output->edid_blob =
    846 		koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
    847 
    848 	if (drmmode_output->edid_blob) {
    849 		ddc_mon = xf86InterpretEDID(output->scrn->scrnIndex,
    850 					    drmmode_output->edid_blob->data);
    851 		if (ddc_mon && drmmode_output->edid_blob->length > 128)
    852 			ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
    853 	}
    854 	xf86OutputSetEDID(output, ddc_mon);
    855 
    856 	drmmode_output_attach_tile(output);
    857 
    858 	/* modes should already be available */
    859 	for (i = 0; i < koutput->count_modes; i++) {
    860 		Mode = XNFalloc(sizeof(DisplayModeRec));
    861 
    862 		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
    863 					 Mode);
    864 		Modes = xf86ModesAdd(Modes, Mode);
    865 
    866 	}
    867 	return Modes;
    868 }
    869 
    870 static void
    871 drmmode_output_destroy(xf86OutputPtr output)
    872 {
    873 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    874 	int i;
    875 
    876 	if (drmmode_output->edid_blob)
    877 		drmModeFreePropertyBlob(drmmode_output->edid_blob);
    878 	if (drmmode_output->tile_blob)
    879 		drmModeFreePropertyBlob(drmmode_output->tile_blob);
    880 	for (i = 0; i < drmmode_output->num_props; i++) {
    881 		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
    882 		free(drmmode_output->props[i].atoms);
    883 	}
    884 	drmModeFreeConnector(drmmode_output->mode_output);
    885 	free(drmmode_output);
    886 	output->driver_private = NULL;
    887 }
    888 
    889 static void
    890 drmmode_output_dpms(xf86OutputPtr output, int mode)
    891 {
    892 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    893 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    894 	drmModePropertyPtr props;
    895 	drmmode_ptr drmmode = drmmode_output->drmmode;
    896 	int mode_id = -1, i;
    897 
    898 	if (!koutput)
    899 		return;
    900 
    901 	for (i = 0; i < koutput->count_props; i++) {
    902 		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
    903 		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
    904 			if (!strcmp(props->name, "DPMS")) {
    905 				mode_id = koutput->props[i];
    906 				drmModeFreeProperty(props);
    907 				break;
    908 			}
    909 			drmModeFreeProperty(props);
    910 		}
    911 	}
    912 
    913 	if (mode_id < 0)
    914 		return;
    915 
    916 	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
    917 				    mode_id, mode);
    918 }
    919 
    920 static Bool
    921 drmmode_property_ignore(drmModePropertyPtr prop)
    922 {
    923 	if (!prop)
    924 	    return TRUE;
    925 	/* ignore blob prop */
    926 	if (prop->flags & DRM_MODE_PROP_BLOB)
    927 		return TRUE;
    928 	/* ignore standard property */
    929 	if (!strcmp(prop->name, "EDID") ||
    930 	    !strcmp(prop->name, "DPMS"))
    931 		return TRUE;
    932 
    933 	return FALSE;
    934 }
    935 
    936 static void
    937 drmmode_output_create_resources(xf86OutputPtr output)
    938 {
    939 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    940 	drmModeConnectorPtr mode_output = drmmode_output->mode_output;
    941 	drmmode_ptr drmmode = drmmode_output->drmmode;
    942 	drmModePropertyPtr drmmode_prop;
    943 	uint32_t value;
    944 	int i, j, err;
    945 
    946 	drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
    947 	if (!drmmode_output->props)
    948 		return;
    949 
    950 	drmmode_output->num_props = 0;
    951 	for (i = 0, j = 0; i < mode_output->count_props; i++) {
    952 		drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
    953 		if (drmmode_property_ignore(drmmode_prop)) {
    954 			drmModeFreeProperty(drmmode_prop);
    955 			continue;
    956 		}
    957 		drmmode_output->props[j].mode_prop = drmmode_prop;
    958 		drmmode_output->props[j].index = i;
    959 		drmmode_output->num_props++;
    960 		j++;
    961 	}
    962 
    963 	for (i = 0; i < drmmode_output->num_props; i++) {
    964 		drmmode_prop_ptr p = &drmmode_output->props[i];
    965 		drmmode_prop = p->mode_prop;
    966 
    967 		value = drmmode_output->mode_output->prop_values[p->index];
    968 
    969 		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
    970 			INT32 range[2];
    971 
    972 			p->num_atoms = 1;
    973 			p->atoms = calloc(p->num_atoms, sizeof(Atom));
    974 			if (!p->atoms)
    975 				continue;
    976 			p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
    977 			range[0] = drmmode_prop->values[0];
    978 			range[1] = drmmode_prop->values[1];
    979 			err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
    980 							FALSE, TRUE,
    981 							drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
    982 							2, range);
    983 			if (err != 0) {
    984 				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    985 					   "RRConfigureOutputProperty error, %d\n", err);
    986 			}
    987 			err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
    988 						     XA_INTEGER, 32, PropModeReplace, 1,
    989 						     &value, FALSE, FALSE);
    990 			if (err != 0) {
    991 				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    992 					   "RRChangeOutputProperty error, %d\n", err);
    993 			}
    994 		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
    995 			p->num_atoms = drmmode_prop->count_enums + 1;
    996 			p->atoms = calloc(p->num_atoms, sizeof(Atom));
    997 			if (!p->atoms)
    998 				continue;
    999 			p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
   1000 			for (j = 1; j <= drmmode_prop->count_enums; j++) {
   1001 				struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
   1002 				p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
   1003 			}
   1004 			err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
   1005 							FALSE, FALSE,
   1006 							drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
   1007 							p->num_atoms - 1, (INT32 *)&p->atoms[1]);
   1008 			if (err != 0) {
   1009 				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1010 					   "RRConfigureOutputProperty error, %d\n", err);
   1011 			}
   1012 			for (j = 0; j < drmmode_prop->count_enums; j++)
   1013 				if (drmmode_prop->enums[j].value == value)
   1014 					break;
   1015 			/* there's always a matching value */
   1016 			err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   1017 						     XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
   1018 			if (err != 0) {
   1019 				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   1020 					   "RRChangeOutputProperty error, %d\n", err);
   1021 			}
   1022 		}
   1023 	}
   1024 }
   1025 
   1026 static Bool
   1027 drmmode_output_set_property(xf86OutputPtr output, Atom property,
   1028 			    RRPropertyValuePtr value)
   1029 {
   1030 	drmmode_output_private_ptr drmmode_output = output->driver_private;
   1031 	drmmode_ptr drmmode = drmmode_output->drmmode;
   1032 	int i, ret;
   1033 
   1034 	for (i = 0; i < drmmode_output->num_props; i++) {
   1035 		drmmode_prop_ptr p = &drmmode_output->props[i];
   1036 
   1037 		if (p->atoms[0] != property)
   1038 			continue;
   1039 
   1040 		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
   1041 			uint32_t val;
   1042 
   1043 			if (value->type != XA_INTEGER || value->format != 32 ||
   1044 			    value->size != 1)
   1045 				return FALSE;
   1046 			val = *(uint32_t *)value->data;
   1047 
   1048 			ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
   1049 							  p->mode_prop->prop_id, (uint64_t)val);
   1050 
   1051 			if (ret)
   1052 				return FALSE;
   1053 
   1054 			return TRUE;
   1055 
   1056 		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
   1057 			Atom	atom;
   1058 			const char	*name;
   1059 			int		j;
   1060 
   1061 			if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
   1062 				return FALSE;
   1063 			memcpy(&atom, value->data, 4);
   1064 			if (!(name = NameForAtom(atom)))
   1065 				return FALSE;
   1066 
   1067 			/* search for matching name string, then set its value down */
   1068 			for (j = 0; j < p->mode_prop->count_enums; j++) {
   1069 				if (!strcmp(p->mode_prop->enums[j].name, name)) {
   1070 					ret = drmModeConnectorSetProperty(drmmode->fd,
   1071 									  drmmode_output->output_id,
   1072 									  p->mode_prop->prop_id,
   1073 									  p->mode_prop->enums[j].value);
   1074 
   1075 					if (ret)
   1076 						return FALSE;
   1077 
   1078 					return TRUE;
   1079 				}
   1080 			}
   1081 
   1082 			return FALSE;
   1083 		}
   1084 	}
   1085 
   1086 	return TRUE;
   1087 }
   1088 
   1089 static Bool
   1090 drmmode_output_get_property(xf86OutputPtr output, Atom property)
   1091 {
   1092 
   1093 	drmmode_output_private_ptr drmmode_output = output->driver_private;
   1094 	drmmode_ptr drmmode = drmmode_output->drmmode;
   1095 	uint32_t value;
   1096 	int err, i;
   1097 
   1098 	if (output->scrn->vtSema) {
   1099 		drmModeFreeConnector(drmmode_output->mode_output);
   1100 		drmmode_output->mode_output =
   1101 			drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
   1102 	}
   1103 
   1104 	if (!drmmode_output->mode_output)
   1105 		return FALSE;
   1106 
   1107 	for (i = 0; i < drmmode_output->num_props; i++) {
   1108 		drmmode_prop_ptr p = &drmmode_output->props[i];
   1109 		if (p->atoms[0] != property)
   1110 			continue;
   1111 
   1112 		value = drmmode_output->mode_output->prop_values[p->index];
   1113 
   1114 		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
   1115 			err = RRChangeOutputProperty(output->randr_output,
   1116 						     property, XA_INTEGER, 32,
   1117 						     PropModeReplace, 1, &value,
   1118 						     FALSE, FALSE);
   1119 
   1120 			return !err;
   1121 		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
   1122 			int		j;
   1123 
   1124 			/* search for matching name string, then set its value down */
   1125 			for (j = 0; j < p->mode_prop->count_enums; j++) {
   1126 				if (p->mode_prop->enums[j].value == value)
   1127 					break;
   1128 			}
   1129 
   1130 			err = RRChangeOutputProperty(output->randr_output, property,
   1131 						     XA_ATOM, 32, PropModeReplace, 1,
   1132 						     &p->atoms[j+1], FALSE, FALSE);
   1133 
   1134 			return !err;
   1135 		}
   1136 	}
   1137 
   1138 	return FALSE;
   1139 }
   1140 
   1141 static const xf86OutputFuncsRec drmmode_output_funcs = {
   1142 	.create_resources = drmmode_output_create_resources,
   1143 	.dpms = drmmode_output_dpms,
   1144 	.detect = drmmode_output_detect,
   1145 	.mode_valid = drmmode_output_mode_valid,
   1146 	.get_modes = drmmode_output_get_modes,
   1147 	.set_property = drmmode_output_set_property,
   1148 	.get_property = drmmode_output_get_property,
   1149 	.destroy = drmmode_output_destroy
   1150 };
   1151 
   1152 static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
   1153 				      SubPixelHorizontalRGB,
   1154 				      SubPixelHorizontalBGR,
   1155 				      SubPixelVerticalRGB,
   1156 				      SubPixelVerticalBGR,
   1157 				      SubPixelNone };
   1158 
   1159 const char *output_names[] = { "None",
   1160 			       "VGA",
   1161 			       "DVI-I",
   1162 			       "DVI-D",
   1163 			       "DVI-A",
   1164 			       "Composite",
   1165 			       "SVIDEO",
   1166 			       "LVDS",
   1167 			       "CTV",
   1168 			       "DIN",
   1169 			       "DP",
   1170 			       "HDMI",
   1171 			       "HDMI",
   1172 			       "TV",
   1173 			       "eDP",
   1174 };
   1175 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
   1176 
   1177 static Bool
   1178 drmmode_zaphod_match(ScrnInfoPtr pScrn, const char *s, char *output_name)
   1179 {
   1180     int i = 0;
   1181     char s1[20];
   1182 
   1183     do {
   1184 	switch(*s) {
   1185 	case ',':
   1186 	    s1[i] = '\0';
   1187 	    i = 0;
   1188 	    if (strcmp(s1, output_name) == 0)
   1189 		return TRUE;
   1190 	    break;
   1191 	case ' ':
   1192 	case '\t':
   1193 	case '\n':
   1194 	case '\r':
   1195 	    break;
   1196 	default:
   1197 	    s1[i] = *s;
   1198 	    i++;
   1199 	    break;
   1200 	}
   1201     } while(*s++);
   1202 
   1203     s1[i] = '\0';
   1204     if (strcmp(s1, output_name) == 0)
   1205 	return TRUE;
   1206 
   1207     return FALSE;
   1208 }
   1209 
   1210 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
   1211 {
   1212 	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   1213 	int i;
   1214 	for (i = 0; i < xf86_config->num_output; i++) {
   1215 		xf86OutputPtr output = xf86_config->output[i];
   1216 		drmmode_output_private_ptr drmmode_output;
   1217 
   1218 		drmmode_output = output->driver_private;
   1219 		if (drmmode_output->output_id == id)
   1220 			return output;
   1221 	}
   1222 	return NULL;
   1223 }
   1224 
   1225 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
   1226 {
   1227 	char *conn;
   1228 	char conn_id[5];
   1229 	int id, len;
   1230 	char *blob_data;
   1231 
   1232 	if (!path_blob)
   1233 		return -1;
   1234 
   1235 	blob_data = path_blob->data;
   1236 	/* we only handle MST paths for now */
   1237 	if (strncmp(blob_data, "mst:", 4))
   1238 		return -1;
   1239 
   1240 	conn = strchr(blob_data + 4, '-');
   1241 	if (!conn)
   1242 		return -1;
   1243 	len = conn - (blob_data + 4);
   1244 	if (len + 1 > 5)
   1245 		return -1;
   1246 	memcpy(conn_id, blob_data + 4, len);
   1247 	conn_id[len] = '\0';
   1248 	id = strtoul(conn_id, NULL, 10);
   1249 
   1250 	*conn_base_id = id;
   1251 
   1252 	*path = conn + 1;
   1253 	return 0;
   1254 }
   1255 
   1256 static void
   1257 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
   1258                     drmModePropertyBlobPtr path_blob)
   1259 {
   1260 	int ret;
   1261 	char *extra_path;
   1262 	int conn_id;
   1263 	xf86OutputPtr output;
   1264 
   1265 	ret = parse_path_blob(path_blob, &conn_id, &extra_path);
   1266 	if (ret == -1)
   1267 		goto fallback;
   1268 
   1269 	output = find_output(pScrn, conn_id);
   1270 	if (!output)
   1271 		goto fallback;
   1272 
   1273 	snprintf(name, 32, "%s-%s", output->name, extra_path);
   1274 	return;
   1275 
   1276 fallback:
   1277 	if (koutput->connector_type >= ARRAY_SIZE(output_names))
   1278 		snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
   1279 	else if (pScrn->is_gpu)
   1280 		snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
   1281 	else
   1282 		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
   1283 }
   1284 
   1285 static unsigned int
   1286 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
   1287 {
   1288 	NVPtr pNv = NVPTR(pScrn);
   1289 	xf86OutputPtr output;
   1290 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   1291 	drmModeConnectorPtr koutput;
   1292 	drmModeEncoderPtr kencoder;
   1293 	drmmode_output_private_ptr drmmode_output;
   1294 	const char *s;
   1295 	char name[32];
   1296 	drmModePropertyBlobPtr path_blob = NULL;
   1297 	int i;
   1298 
   1299 	koutput = drmModeGetConnector(drmmode->fd,
   1300 				      mode_res->connectors[num]);
   1301 	if (!koutput)
   1302 		return 0;
   1303 
   1304 	path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
   1305 
   1306 	drmmode_create_name(pScrn, koutput, name, path_blob);
   1307 
   1308 	if (path_blob)
   1309 		drmModeFreePropertyBlob(path_blob);
   1310 
   1311 	if (path_blob && dynamic) {
   1312 		/* see if we have an output with this name already
   1313 		   and hook stuff up */
   1314 		for (i = 0; i < xf86_config->num_output; i++) {
   1315 			output = xf86_config->output[i];
   1316 
   1317 			if (strncmp(output->name, name, 32))
   1318 				continue;
   1319 
   1320 			drmmode_output = output->driver_private;
   1321 			drmmode_output->output_id = mode_res->connectors[num];
   1322 			drmmode_output->mode_output = koutput;
   1323 			return 1;
   1324 		}
   1325 	}
   1326 
   1327 
   1328 	kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
   1329 	if (!kencoder) {
   1330 		drmModeFreeConnector(koutput);
   1331 		return 0;
   1332 	}
   1333 
   1334 	if (xf86IsEntityShared(pScrn->entityList[0])) {
   1335 		s = xf86GetOptValString(pNv->Options, OPTION_ZAPHOD_HEADS);
   1336 		if (s) {
   1337 			if (!drmmode_zaphod_match(pScrn, s, name)) {
   1338 				drmModeFreeEncoder(kencoder);
   1339 				drmModeFreeConnector(koutput);
   1340 				return 0;
   1341 			}
   1342 		} else {
   1343 			if (pNv->Primary && (num != 0)) {
   1344 				drmModeFreeEncoder(kencoder);
   1345 				drmModeFreeConnector(koutput);
   1346 				return 0;
   1347 			} else
   1348 			if (pNv->Secondary && (num != 1)) {
   1349 				drmModeFreeEncoder(kencoder);
   1350 				drmModeFreeConnector(koutput);
   1351 				return 0;
   1352 			}
   1353 		}
   1354 	}
   1355 
   1356 	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
   1357 	if (!output) {
   1358 		drmModeFreeEncoder(kencoder);
   1359 		drmModeFreeConnector(koutput);
   1360 		return 0;
   1361 	}
   1362 
   1363 	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
   1364 	if (!drmmode_output) {
   1365 		xf86OutputDestroy(output);
   1366 		drmModeFreeConnector(koutput);
   1367 		drmModeFreeEncoder(kencoder);
   1368 		return 0;
   1369 	}
   1370 
   1371 	drmmode_output->output_id = mode_res->connectors[num];
   1372 	drmmode_output->mode_output = koutput;
   1373 	drmmode_output->mode_encoder = kencoder;
   1374 	drmmode_output->drmmode = drmmode;
   1375 	output->mm_width = koutput->mmWidth;
   1376 	output->mm_height = koutput->mmHeight;
   1377 
   1378 	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
   1379 	output->driver_private = drmmode_output;
   1380 
   1381 	output->possible_crtcs = kencoder->possible_crtcs >> crtcshift;
   1382 	output->possible_clones = kencoder->possible_clones >> crtcshift;
   1383 
   1384 	output->interlaceAllowed = true;
   1385 	output->doubleScanAllowed = true;
   1386 
   1387 	if (dynamic)
   1388 		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
   1389 
   1390 	return 1;
   1391 }
   1392 
   1393 static Bool
   1394 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
   1395 {
   1396 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   1397 	ScreenPtr screen = xf86ScrnToScreen(scrn);
   1398 	NVPtr pNv = NVPTR(scrn);
   1399 	drmmode_crtc_private_ptr drmmode_crtc = NULL;
   1400 	drmmode_ptr drmmode = NULL;
   1401 	uint32_t old_width, old_height, old_pitch, old_fb_id = 0;
   1402 	struct nouveau_bo *old_bo = NULL;
   1403 	int ret, i, pitch;
   1404 	PixmapPtr ppix;
   1405 
   1406 	if (xf86_config->num_crtc) {
   1407 		drmmode_crtc = xf86_config->crtc[0]->driver_private;
   1408 		drmmode = drmmode_crtc->drmmode;
   1409 	}
   1410 	ErrorF("resize called %d %d\n", width, height);
   1411 
   1412 	if (scrn->virtualX == width && scrn->virtualY == height)
   1413 		return TRUE;
   1414 
   1415 	old_width = scrn->virtualX;
   1416 	old_height = scrn->virtualY;
   1417 	old_pitch = scrn->displayWidth;
   1418 	if (drmmode)
   1419 		old_fb_id = drmmode->fb_id;
   1420 	nouveau_bo_ref(pNv->scanout, &old_bo);
   1421 	nouveau_bo_ref(NULL, &pNv->scanout);
   1422 
   1423 	ret = nouveau_allocate_surface(scrn, width, height,
   1424 				       scrn->bitsPerPixel,
   1425 				       NOUVEAU_CREATE_PIXMAP_SCANOUT,
   1426 				       &pitch, &pNv->scanout);
   1427 	if (!ret)
   1428 		goto fail;
   1429 
   1430 	scrn->virtualX = width;
   1431 	scrn->virtualY = height;
   1432 	scrn->displayWidth = pitch / (scrn->bitsPerPixel >> 3);
   1433 
   1434 	nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client);
   1435 
   1436 	if (drmmode) {
   1437 		ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
   1438 				  scrn->bitsPerPixel, pitch, pNv->scanout->handle,
   1439 				  &drmmode->fb_id);
   1440 		if (ret)
   1441 			goto fail;
   1442 	}
   1443 
   1444 	if (pNv->ShadowPtr) {
   1445 		free(pNv->ShadowPtr);
   1446 		pNv->ShadowPitch = pitch;
   1447 		pNv->ShadowPtr = malloc(pNv->ShadowPitch * height);
   1448 	}
   1449 
   1450 	ppix = screen->GetScreenPixmap(screen);
   1451 	if (pNv->AccelMethod > NONE)
   1452 		nouveau_bo_ref(pNv->scanout, &drmmode_pixmap(ppix)->bo);
   1453 	screen->ModifyPixmapHeader(ppix, width, height, -1, -1, pitch,
   1454 				   (pNv->AccelMethod > NONE || pNv->ShadowPtr) ?
   1455 				   pNv->ShadowPtr : pNv->scanout->map);
   1456 
   1457 	if (pNv->AccelMethod == EXA) {
   1458 		pNv->EXADriverPtr->PrepareSolid(ppix, GXcopy, ~0, 0);
   1459 		pNv->EXADriverPtr->Solid(ppix, 0, 0, width, height);
   1460 		pNv->EXADriverPtr->DoneSolid(ppix);
   1461 		nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client);
   1462 	} else {
   1463 		memset(pNv->scanout->map, 0x00, pNv->scanout->size);
   1464 	}
   1465 
   1466 	for (i = 0; i < xf86_config->num_crtc; i++) {
   1467 		xf86CrtcPtr crtc = xf86_config->crtc[i];
   1468 
   1469 		if (!crtc->enabled)
   1470 			continue;
   1471 
   1472 		drmmode_set_mode_major(crtc, &crtc->mode,
   1473 				       crtc->rotation, crtc->x, crtc->y);
   1474 	}
   1475 
   1476 	if (old_fb_id)
   1477 		drmModeRmFB(drmmode->fd, old_fb_id);
   1478 	nouveau_bo_ref(NULL, &old_bo);
   1479 
   1480 	return TRUE;
   1481 
   1482  fail:
   1483 	nouveau_bo_ref(old_bo, &pNv->scanout);
   1484 	scrn->virtualX = old_width;
   1485 	scrn->virtualY = old_height;
   1486 	scrn->displayWidth = old_pitch;
   1487 	if (drmmode)
   1488 		drmmode->fb_id = old_fb_id;
   1489 
   1490 	return FALSE;
   1491 }
   1492 
   1493 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
   1494 	drmmode_xf86crtc_resize
   1495 };
   1496 
   1497 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
   1498 {
   1499 	drmmode_ptr drmmode;
   1500 	drmModeResPtr mode_res;
   1501 	NVEntPtr pNVEnt = NVEntPriv(pScrn);
   1502 	int i;
   1503 	unsigned int crtcs_needed = 0;
   1504 	int crtcshift;
   1505 
   1506 	drmmode = XNFcallocarray(sizeof(*drmmode), 1);
   1507 	drmmode->fd = fd;
   1508 	drmmode->fb_id = 0;
   1509 
   1510 	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
   1511 
   1512 	drmmode->cpp = cpp;
   1513 	mode_res = drmModeGetResources(drmmode->fd);
   1514 	if (!mode_res)
   1515 		return FALSE;
   1516 
   1517 	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
   1518 			     mode_res->max_height);
   1519 
   1520 	if (!mode_res->count_connectors ||
   1521 	    !mode_res->count_crtcs) {
   1522 		free(drmmode);
   1523 		goto done;
   1524 	}
   1525 
   1526 	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing outputs ...\n");
   1527 	crtcshift = ffs(pNVEnt->assigned_crtcs ^ 0xffffffff) - 1;
   1528 	for (i = 0; i < mode_res->count_connectors; i++)
   1529 		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE, crtcshift);
   1530 
   1531 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
   1532 		   "%d crtcs needed for screen.\n", crtcs_needed);
   1533 
   1534 	for (i = 0; i < mode_res->count_crtcs; i++) {
   1535 		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
   1536 		    (crtcs_needed && !(pNVEnt->assigned_crtcs & (1 << i))))
   1537 			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
   1538 	}
   1539 
   1540 	/* All ZaphodHeads outputs provided with matching crtcs? */
   1541 	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
   1542 		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
   1543 			   "%d ZaphodHeads crtcs unavailable. Trouble!\n",
   1544 			   crtcs_needed);
   1545 
   1546 done:
   1547 	drmModeFreeResources(mode_res);
   1548 
   1549 #ifdef NOUVEAU_PIXMAP_SHARING
   1550 	xf86ProviderSetup(pScrn, NULL, "nouveau");
   1551 #endif
   1552 
   1553 	xf86InitialConfiguration(pScrn, TRUE);
   1554 
   1555 	return TRUE;
   1556 }
   1557 
   1558 void
   1559 drmmode_adjust_frame(ScrnInfoPtr scrn, int x, int y)
   1560 {
   1561 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
   1562 	xf86OutputPtr output = config->output[config->compat_output];
   1563 	xf86CrtcPtr crtc = output->crtc;
   1564 
   1565 	if (!crtc || !crtc->enabled)
   1566 		return;
   1567 
   1568 	drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
   1569 }
   1570 
   1571 void
   1572 drmmode_remove_fb(ScrnInfoPtr pScrn)
   1573 {
   1574 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
   1575 	xf86CrtcPtr crtc = NULL;
   1576 	drmmode_crtc_private_ptr drmmode_crtc;
   1577 	drmmode_ptr drmmode;
   1578 
   1579 	if (config && config->num_crtc)
   1580 		crtc = config->crtc[0];
   1581 	if (!crtc)
   1582 		return;
   1583 
   1584 	drmmode_crtc = crtc->driver_private;
   1585 	drmmode = drmmode_crtc->drmmode;
   1586 
   1587 	if (drmmode->fb_id)
   1588 		drmModeRmFB(drmmode->fd, drmmode->fb_id);
   1589 	drmmode->fb_id = 0;
   1590 }
   1591 
   1592 int
   1593 drmmode_cursor_init(ScreenPtr pScreen)
   1594 {
   1595 	NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen));
   1596 	int size = nv_cursor_width(pNv);
   1597 	int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
   1598 		    HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
   1599 		    (pNv->dev->chipset >= 0x11 ? HARDWARE_CURSOR_ARGB : 0) |
   1600 		    HARDWARE_CURSOR_UPDATE_UNHIDDEN;
   1601 
   1602 	return xf86_cursors_init(pScreen, size, size, flags);
   1603 }
   1604 
   1605 #ifdef HAVE_LIBUDEV
   1606 
   1607 #define DRM_MODE_LINK_STATUS_GOOD       0
   1608 #define DRM_MODE_LINK_STATUS_BAD        1
   1609 
   1610 static void
   1611 drmmode_handle_uevents(ScrnInfoPtr scrn)
   1612 {
   1613     struct udev_device *dev;
   1614     drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1615     drmModeResPtr mode_res;
   1616     xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
   1617     int i, j;
   1618     Bool found = FALSE;
   1619     Bool changed = FALSE;
   1620 
   1621     while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
   1622         udev_device_unref(dev);
   1623         found = TRUE;
   1624     }
   1625     if (!found)
   1626         return;
   1627 
   1628     /* Try to re-set the mode on all the connectors with a BAD link-state:
   1629      * This may happen if a link degrades and a new modeset is necessary, using
   1630      * different link-training parameters. If the kernel found that the current
   1631      * mode is not achievable anymore, it should have pruned the mode before
   1632      * sending the hotplug event. Try to re-set the currently-set mode to keep
   1633      * the display alive, this will fail if the mode has been pruned.
   1634      * In any case, we will send randr events for the Desktop Environment to
   1635      * deal with it, if it wants to.
   1636      */
   1637     for (i = 0; i < config->num_output; i++) {
   1638         xf86OutputPtr output = config->output[i];
   1639         xf86CrtcPtr crtc = output->crtc;
   1640         drmmode_output_private_ptr drmmode_output = output->driver_private;
   1641         uint32_t con_id, idx;
   1642         drmModeConnectorPtr koutput;
   1643 
   1644         if (crtc == NULL || drmmode_output->mode_output == NULL)
   1645             continue;
   1646 
   1647         con_id = drmmode_output->mode_output->connector_id;
   1648         /* Get an updated view of the properties for the current connector and
   1649          * look for the link-status property
   1650          */
   1651         koutput = drmModeGetConnectorCurrent(drmmode->fd, con_id);
   1652         if (!koutput)
   1653             continue;
   1654 
   1655         idx = koutput_get_prop_idx(drmmode->fd, koutput,
   1656                 DRM_MODE_PROP_ENUM, "link-status");
   1657 
   1658         if ((idx > -1) &&
   1659                 (koutput->prop_values[idx] == DRM_MODE_LINK_STATUS_BAD)) {
   1660             /* the connector got a link failure, re-set the current mode */
   1661             drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
   1662                                    crtc->x, crtc->y);
   1663 
   1664             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
   1665                        "hotplug event: connector %u's link-state is BAD, "
   1666                        "tried resetting the current mode. You may be left"
   1667                        "with a black screen if this fails...\n", con_id);
   1668         }
   1669 
   1670         drmModeFreeConnector(koutput);
   1671     }
   1672 
   1673     mode_res = drmModeGetResources(drmmode->fd);
   1674     if (!mode_res)
   1675         goto out;
   1676 
   1677     if (mode_res->count_crtcs != config->num_crtc) {
   1678         ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc);
   1679         goto out_free_res;
   1680     }
   1681 
   1682     /* figure out if we have gotten rid of any connectors
   1683        traverse old output list looking for outputs */
   1684     for (i = 0; i < config->num_output; i++) {
   1685         xf86OutputPtr output = config->output[i];
   1686         drmmode_output_private_ptr drmmode_output;
   1687 
   1688         drmmode_output = output->driver_private;
   1689         found = FALSE;
   1690         for (j = 0; j < mode_res->count_connectors; j++) {
   1691             if (mode_res->connectors[j] == drmmode_output->output_id) {
   1692                 found = TRUE;
   1693                 break;
   1694             }
   1695         }
   1696         if (found)
   1697             continue;
   1698 
   1699         drmModeFreeConnector(drmmode_output->mode_output);
   1700         drmmode_output->mode_output = NULL;
   1701         drmmode_output->output_id = -1;
   1702 
   1703         changed = TRUE;
   1704     }
   1705 
   1706     /* find new output ids we don't have outputs for */
   1707     for (i = 0; i < mode_res->count_connectors; i++) {
   1708         found = FALSE;
   1709 
   1710         for (j = 0; j < config->num_output; j++) {
   1711             xf86OutputPtr output = config->output[j];
   1712             drmmode_output_private_ptr drmmode_output;
   1713 
   1714             drmmode_output = output->driver_private;
   1715             if (mode_res->connectors[i] == drmmode_output->output_id) {
   1716                 found = TRUE;
   1717                 break;
   1718             }
   1719         }
   1720         if (found)
   1721             continue;
   1722 
   1723         changed = TRUE;
   1724         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
   1725     }
   1726 
   1727     if (changed) {
   1728         RRSetChanged(xf86ScrnToScreen(scrn));
   1729         RRTellChanged(xf86ScrnToScreen(scrn));
   1730     }
   1731 
   1732 out_free_res:
   1733     drmModeFreeResources(mode_res);
   1734 out:
   1735     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
   1736 }
   1737 
   1738 #undef DRM_MODE_LINK_STATUS_BAD
   1739 #undef DRM_MODE_LINK_STATUS_GOOD
   1740 
   1741 #endif
   1742 
   1743 #ifdef HAVE_LIBUDEV
   1744 #if HAVE_NOTIFY_FD
   1745 static void
   1746 drmmode_udev_notify(int fd, int notify, void *data)
   1747 {
   1748 	ScrnInfoPtr scrn = data;
   1749 	drmmode_handle_uevents(scrn);
   1750 }
   1751 #endif
   1752 #endif
   1753 
   1754 static bool has_randr(void)
   1755 {
   1756 	return dixPrivateKeyRegistered(rrPrivKey);
   1757 }
   1758 
   1759 static void
   1760 drmmode_uevent_init(ScrnInfoPtr scrn)
   1761 {
   1762 #ifdef HAVE_LIBUDEV
   1763 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1764 	struct udev *u;
   1765 	struct udev_monitor *mon;
   1766 
   1767 	/* RandR will be disabled if Xinerama is active, and so generating
   1768 	 * RR hotplug events is then forbidden.
   1769 	 */
   1770 	if (!has_randr())
   1771 		return;
   1772 
   1773 	u = udev_new();
   1774 	if (!u)
   1775 		return;
   1776 	mon = udev_monitor_new_from_netlink(u, "udev");
   1777 	if (!mon) {
   1778 		udev_unref(u);
   1779 		return;
   1780 	}
   1781 
   1782 	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
   1783 							    "drm",
   1784 							    "drm_minor") < 0 ||
   1785 	    udev_monitor_enable_receiving(mon) < 0) {
   1786 		udev_monitor_unref(mon);
   1787 		udev_unref(u);
   1788 		return;
   1789 	}
   1790 
   1791 #if HAVE_NOTIFY_FD
   1792 	SetNotifyFd(udev_monitor_get_fd(mon), drmmode_udev_notify, X_NOTIFY_READ, scrn);
   1793 #else
   1794 	AddGeneralSocket(udev_monitor_get_fd(mon));
   1795 #endif
   1796 	drmmode->uevent_monitor = mon;
   1797 #endif
   1798 }
   1799 
   1800 static void
   1801 drmmode_uevent_fini(ScrnInfoPtr scrn)
   1802 {
   1803 #ifdef HAVE_LIBUDEV
   1804 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1805 
   1806 	if (drmmode->uevent_monitor) {
   1807 		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
   1808 
   1809 #if HAVE_NOTIFY_FD
   1810 		RemoveNotifyFd(udev_monitor_get_fd(drmmode->uevent_monitor));
   1811 #else
   1812 		RemoveGeneralSocket(udev_monitor_get_fd(drmmode->uevent_monitor));
   1813 #endif
   1814 		udev_monitor_unref(drmmode->uevent_monitor);
   1815 		udev_unref(u);
   1816 	}
   1817 #endif
   1818 }
   1819 
   1820 #if HAVE_NOTIFY_FD
   1821 static void
   1822 drmmode_notify_fd(int fd, int notify, void *data)
   1823 {
   1824 	ScrnInfoPtr scrn = data;
   1825 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1826 	drmHandleEvent(drmmode->fd, &drmmode->event_context);
   1827 }
   1828 #else
   1829 
   1830 static void
   1831 drmmode_wakeup_handler(pointer data, int err, pointer p)
   1832 {
   1833 	ScrnInfoPtr scrn = data;
   1834 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1835 	fd_set *read_mask = p;
   1836 
   1837 	if (scrn == NULL || err < 0)
   1838 		return;
   1839 
   1840 	if (FD_ISSET(drmmode->fd, read_mask))
   1841 		drmHandleEvent(drmmode->fd, &drmmode->event_context);
   1842 
   1843 #ifdef HAVE_LIBUDEV
   1844 	if (FD_ISSET(udev_monitor_get_fd(drmmode->uevent_monitor), read_mask))
   1845 		drmmode_handle_uevents(scrn);
   1846 #endif
   1847 }
   1848 #endif
   1849 
   1850 void
   1851 drmmode_screen_init(ScreenPtr pScreen)
   1852 {
   1853 	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   1854 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1855 	NVEntPtr pNVEnt = NVEntPriv(scrn);
   1856 
   1857 	/* Setup handler for DRM events */
   1858 	drmmode_event_init(scrn);
   1859 
   1860 	/* Setup handler for udevevents */
   1861 	drmmode_uevent_init(scrn);
   1862 
   1863 	/* Register wakeup handler only once per servergen, so ZaphodHeads work */
   1864 	if (pNVEnt->fd_wakeup_registered != serverGeneration) {
   1865 		/* Register a wakeup handler to get informed on DRM events */
   1866 #if HAVE_NOTIFY_FD
   1867 		SetNotifyFd(drmmode->fd, drmmode_notify_fd, X_NOTIFY_READ, scrn);
   1868 #else
   1869 		AddGeneralSocket(drmmode->fd);
   1870 		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
   1871 		                               drmmode_wakeup_handler, scrn);
   1872 #endif
   1873 		pNVEnt->fd_wakeup_registered = serverGeneration;
   1874 		pNVEnt->fd_wakeup_ref = 1;
   1875 	}
   1876 	else
   1877 		pNVEnt->fd_wakeup_ref++;
   1878 }
   1879 
   1880 void
   1881 drmmode_screen_fini(ScreenPtr pScreen)
   1882 {
   1883 	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   1884 	drmmode_ptr drmmode = drmmode_from_scrn(scrn);
   1885 	NVEntPtr pNVEnt = NVEntPriv(scrn);
   1886 
   1887 	/* Unregister wakeup handler after last x-screen for this servergen dies. */
   1888 	if (pNVEnt->fd_wakeup_registered == serverGeneration &&
   1889 		!--pNVEnt->fd_wakeup_ref) {
   1890 
   1891 #if HAVE_NOTIFY_FD
   1892 		RemoveNotifyFd(drmmode->fd);
   1893 #else
   1894 		/* Unregister wakeup handler */
   1895 		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
   1896 		                             drmmode_wakeup_handler, scrn);
   1897 		RemoveGeneralSocket(drmmode->fd);
   1898 #endif
   1899 	}
   1900 
   1901 	/* Tear down udev event handler */
   1902 	drmmode_uevent_fini(scrn);
   1903 
   1904 	/* Tear down DRM event handler */
   1905 	drmmode_event_fini(scrn);
   1906 }
   1907