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