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