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