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