randr12: nouveau_output -> nouveau_connector
[nouveau] / src / drmmode_display.c
1 /*
2  * Copyright © 2007 Red Hat, Inc.
3  * Copyright © 2008 Maarten Maathuis
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * Authors:
25  *    Dave Airlie <airlied@redhat.com>
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #ifdef XF86DRM_MODE
34
35 #include "drmmode_display.h"
36 #include "sarea.h"
37 #include "X11/Xatom.h"
38
39 /* not using for the moment */
40 uint32_t drmmode_create_new_fb(ScrnInfoPtr pScrn, int width, int height, int *pitch)
41 {
42 #if NOUVEAU_EXA_PIXMAPS
43         NVPtr pNv = NVPTR(pScrn);
44         int ret = 0;
45
46         /* temporary hack, allow old framebuffers to continue to exist and idle. */
47         if (pNv->FB_old) {
48                 nouveau_bo_del(pNv->FB_old);
49                 pNv->FB_old = NULL;
50         }
51
52         pNv->FB_old = pNv->FB;
53         pNv->FB = NULL;
54
55         *pitch = NOUVEAU_ALIGN(*pitch, 64) * (pScrn->bitsPerPixel >> 3);
56
57         ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,
58                         0, *pitch * NOUVEAU_ALIGN(height, 64), &pNv->FB)
59
60         if (ret)
61                 return 0;
62
63         ret = nouveau_bo_map(pNv->FB, NOUVEAU_BO_RDWR);
64
65         if (ret)
66                 return 0;
67
68         return pNv->FB.handle;
69 #else
70         return 0; /* we have a fixed FB */
71 #endif /* NOUVEAU_EXA_PIXMAPS */
72 }
73
74 #if 0
75 static Bool drmmode_resize_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height);
76 #endif
77
78 static Bool
79 drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
80 {
81         //xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
82         //drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[0]->driver_private;
83         //drmmode_ptr drmmode = drmmode_crtc->drmmode;
84         //Bool ret;
85
86         ErrorF("resize called %d %d\n", width, height);
87         //ret = drmmode_resize_fb(scrn, drmmode, width, height);
88         scrn->virtualX = width;
89         scrn->virtualY = height;
90
91         return TRUE; //ret;
92 }
93
94 static void
95 drmmode_ConvertFromKMode(ScrnInfoPtr    scrn,
96                         struct drm_mode_modeinfo *kmode,
97                         DisplayModePtr  mode)
98 {
99         memset(mode, 0, sizeof(DisplayModeRec));
100         mode->status = MODE_OK;
101
102         mode->Clock = kmode->clock;
103
104         mode->HDisplay = kmode->hdisplay;
105         mode->HSyncStart = kmode->hsync_start;
106         mode->HSyncEnd = kmode->hsync_end;
107         mode->HTotal = kmode->htotal;
108         mode->HSkew = kmode->hskew;
109
110         mode->VDisplay = kmode->vdisplay;
111         mode->VSyncStart = kmode->vsync_start;
112         mode->VSyncEnd = kmode->vsync_end;
113         mode->VTotal = kmode->vtotal;
114         mode->VScan = kmode->vscan;
115
116         mode->Flags = kmode->flags; //& FLAG_BITS;
117         mode->name = strdup(kmode->name);
118
119         if (kmode->type & DRM_MODE_TYPE_DRIVER)
120                 mode->type = M_T_DRIVER;
121         if (kmode->type & DRM_MODE_TYPE_PREFERRED)
122                 mode->type |= M_T_PREFERRED;
123         xf86SetModeCrtc (mode, scrn->adjustFlags);
124 }
125
126 static void
127 drmmode_ConvertToKMode(ScrnInfoPtr      scrn,
128                 struct drm_mode_modeinfo *kmode,
129                 DisplayModePtr  mode)
130 {
131         memset(kmode, 0, sizeof(*kmode));
132
133         kmode->clock = mode->Clock;
134         kmode->hdisplay = mode->HDisplay;
135         kmode->hsync_start = mode->HSyncStart;
136         kmode->hsync_end = mode->HSyncEnd;
137         kmode->htotal = mode->HTotal;
138         kmode->hskew = mode->HSkew;
139
140         kmode->vdisplay = mode->VDisplay;
141         kmode->vsync_start = mode->VSyncStart;
142         kmode->vsync_end = mode->VSyncEnd;
143         kmode->vtotal = mode->VTotal;
144         kmode->vscan = mode->VScan;
145
146         kmode->flags = mode->Flags; //& FLAG_BITS;
147         if (mode->name)
148                 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
149         kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
150
151 }
152
153 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
154         drmmode_xf86crtc_resize
155 };
156
157 static void
158 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
159 {
160         return;
161 }
162
163 static Bool
164 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
165                         Rotation rotation, int x, int y)
166 {
167         xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
168         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
169         drmmode_ptr drmmode = drmmode_crtc->drmmode;
170         int saved_x, saved_y;
171         Rotation saved_rotation;
172         DisplayModeRec saved_mode;
173         uint32_t *output_ids;
174         int output_count = 0;
175         int ret = TRUE;
176         int i;
177         int fb_id;
178         struct drm_mode_modeinfo kmode;
179
180         ErrorF("drmmode_set_mode_major called\n");
181
182         saved_mode = crtc->mode;
183         saved_x = crtc->x;
184         saved_y = crtc->y;
185         saved_rotation = crtc->rotation;
186
187         crtc->mode = *mode;
188         crtc->x = x;
189         crtc->y = y;
190         crtc->rotation = rotation;
191
192         output_ids = xcalloc(sizeof(uint32_t), xf86_config->num_output);
193         if (!output_ids) {
194                 ret = FALSE;
195                 goto done;
196         }
197
198         for (i = 0; i < xf86_config->num_output; i++) {
199                 xf86OutputPtr output = xf86_config->output[i];
200                 drmmode_output_private_ptr drmmode_output;
201
202                 if (output->crtc != crtc)
203                         continue;
204
205                 drmmode_output = output->driver_private;
206                 output_ids[output_count] = drmmode_output->mode_output->connector_id;
207                 output_count++;
208         }
209
210         if (!xf86CrtcRotate(crtc, mode, rotation)) {
211                 goto done;
212         }
213
214         drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
215
216         if (drmmode_crtc->shadow_id && crtc->rotatedData)
217                 fb_id = drmmode_crtc->shadow_id;
218         else
219                 fb_id = drmmode->fb_id;
220         ErrorF("fb id is %d\n", fb_id);
221         drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
222                         fb_id, x, y, output_ids, output_count, &kmode);
223
224 done:
225         if (!ret) {
226                 crtc->x = saved_x;
227                 crtc->y = saved_y;
228                 crtc->rotation = saved_rotation;
229                 crtc->mode = saved_mode;
230         }
231
232         if (output_ids)
233                 xfree(output_ids);
234         return ret;
235 }
236
237 static void
238 drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
239 {
240   
241 }
242
243 static void
244 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
245 {
246         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
247         drmmode_ptr drmmode = drmmode_crtc->drmmode;
248
249         drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
250 }
251
252 static void
253 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
254 {
255         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
256
257         NVPtr pNv = NVPTR(crtc->scrn);
258         uint32_t *dst = NULL;
259
260         if (drmmode_crtc->index == 1)
261                 dst = (uint32_t *) pNv->Cursor2->map;
262         else
263                 dst = (uint32_t *) pNv->Cursor->map;
264
265         /* Assume cursor is 64x64 */
266         memcpy(dst, (uint32_t *)image, 64 * 64 * 4);
267 }
268
269
270 static void
271 drmmode_hide_cursor (xf86CrtcPtr crtc)
272 {
273         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
274         drmmode_ptr drmmode = drmmode_crtc->drmmode;
275
276         drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
277
278 }
279
280 static void
281 drmmode_show_cursor (xf86CrtcPtr crtc)
282 {
283         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
284         drmmode_ptr drmmode = drmmode_crtc->drmmode;
285         NVPtr pNv = NVPTR(crtc->scrn);
286
287         drm_handle_t handle = 0;
288
289         if (drmmode_crtc->index == 1)
290                 handle = pNv->Cursor2->map_handle;
291         else
292                 handle = pNv->Cursor->map_handle;
293
294         drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64);
295 }
296
297 /* This stuff isn't ready for NOUVEAU_EXA_PIXMAPS, but can be easily ported. */
298 static void *
299 drmmode_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
300 {
301         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
302         drmmode_ptr drmmode = drmmode_crtc->drmmode;
303         ScrnInfoPtr pScrn = crtc->scrn;
304         NVPtr pNv = NVPTR(pScrn);
305         int size, pitch, ret;
306
307         ErrorF("drmmode_shadow_allocate\n");
308
309         pitch = width * (pScrn->bitsPerPixel/8);
310         size = pitch * height;
311
312         if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN,
313                         64, size, &drmmode_crtc->shadow)) {
314                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate memory for shadow buffer!\n");
315                 return NULL;
316         }
317
318         if (drmmode_crtc->shadow && nouveau_bo_map(drmmode_crtc->shadow, NOUVEAU_BO_RDWR)) {
319                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
320                                 "Failed to map shadow buffer.\n");
321                 return NULL;
322         }
323
324         ret = drmModeAddFB(drmmode->fd, width, height, pScrn->depth, pScrn->bitsPerPixel, pitch, drmmode_crtc->shadow->map_handle, &drmmode_crtc->shadow_id);
325         if (ret)
326                 return NULL;
327
328         /* for easy acces by exa */
329         pNv->shadow[drmmode_crtc->index] = drmmode_crtc->shadow;
330
331         return drmmode_crtc->shadow->map;
332 }
333
334 static PixmapPtr
335 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
336 {
337         ScrnInfoPtr pScrn = crtc->scrn;
338         uint32_t pitch;
339         PixmapPtr rotate_pixmap;
340
341         ErrorF("drmmode_shadow_create\n");
342
343         if (!data)
344                 data = crtc->funcs->shadow_allocate (crtc, width, height);
345
346         pitch = width * (pScrn->bitsPerPixel/8);
347
348         rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
349                                                 width, height,
350                                                 pScrn->depth,
351                                                 pScrn->bitsPerPixel,
352                                                 pitch,
353                                                 data);
354
355         if (rotate_pixmap == NULL) {
356                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
357                         "Couldn't allocate shadow pixmap for rotated CRTC\n");
358         }
359
360         return rotate_pixmap;
361 }
362
363 static void
364 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
365 {
366         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
367         drmmode_ptr drmmode = drmmode_crtc->drmmode;
368         ScrnInfoPtr pScrn = crtc->scrn;
369         NVPtr pNv = NVPTR(pScrn);
370         ScreenPtr pScreen = pScrn->pScreen;
371
372         ErrorF("drmmode_shadow_destroy\n");
373
374         if (rotate_pixmap)
375                 pScreen->DestroyPixmap(rotate_pixmap);
376
377         if (drmmode_crtc->shadow_id) {
378                 drmModeRmFB(drmmode->fd, drmmode_crtc->shadow_id);
379                 drmmode_crtc->shadow_id = 0;
380         }
381
382         if (drmmode_crtc->shadow)
383                 nouveau_bo_del(&drmmode_crtc->shadow);
384
385         drmmode_crtc->shadow = NULL;
386
387         /* for easy acces by exa */
388         pNv->shadow[drmmode_crtc->index] = NULL;
389 }
390
391 static void
392 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size)
393 {
394         ScrnInfoPtr pScrn = crtc->scrn;
395         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
396         drmmode_ptr drmmode = drmmode_crtc->drmmode;
397         int ret;
398
399         ErrorF("drmmode_gamma_set\n");
400
401         ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, size, (uint16_t *)red, (uint16_t *)green, (uint16_t *)blue);
402         if (ret)
403                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drmModeCrtcSetGamma failed\n");
404 }
405
406 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
407         .dpms = drmmode_crtc_dpms,
408         .set_mode_major = drmmode_set_mode_major,
409         .set_cursor_colors = drmmode_set_cursor_colors,
410         .set_cursor_position = drmmode_set_cursor_position,
411         .show_cursor = drmmode_show_cursor,
412         .hide_cursor = drmmode_hide_cursor,
413         .load_cursor_argb = drmmode_load_cursor_argb,
414         .shadow_create = drmmode_shadow_create,
415         .shadow_allocate = drmmode_shadow_allocate,
416         .shadow_destroy = drmmode_shadow_destroy,
417         .gamma_set = drmmode_gamma_set,
418         .destroy = NULL, /* XXX */
419 };
420
421
422 static void
423 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
424 {
425         xf86CrtcPtr crtc;
426         drmmode_crtc_private_ptr drmmode_crtc;
427
428         crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
429         if (crtc == NULL)
430                 return;
431
432         drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
433         drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
434         drmmode_crtc->drmmode = drmmode;
435         drmmode_crtc->index = num;
436         crtc->driver_private = drmmode_crtc;
437
438         return;
439 }
440
441 static xf86OutputStatus
442 drmmode_output_detect(xf86OutputPtr output)
443 {
444         /* go to the hw and retrieve a new output struct */
445         drmmode_output_private_ptr drmmode_output = output->driver_private;
446         drmmode_ptr drmmode = drmmode_output->drmmode;
447         xf86OutputStatus status;
448         drmModeFreeConnector(drmmode_output->mode_output);
449
450         ErrorF("drmmode_output_detect called\n");
451
452         drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
453
454         switch (drmmode_output->mode_output->connection) {
455         case DRM_MODE_CONNECTED:
456                 status = XF86OutputStatusConnected;
457                 break;
458         case DRM_MODE_DISCONNECTED:
459                 status = XF86OutputStatusDisconnected;
460                 break;
461         default:
462         case DRM_MODE_UNKNOWNCONNECTION:
463                 status = XF86OutputStatusUnknown;
464                 break;
465         }
466         return status;
467 }
468
469 static Bool
470 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
471 {
472         return MODE_OK;
473 }
474
475 static DisplayModePtr
476 drmmode_output_get_modes(xf86OutputPtr output)
477 {
478         drmmode_output_private_ptr drmmode_output = output->driver_private;
479         drmModeConnectorPtr koutput = drmmode_output->mode_output;
480         drmmode_ptr drmmode = drmmode_output->drmmode;
481         int i;
482         DisplayModePtr Modes = NULL, Mode;
483         drmModePropertyPtr props;
484
485         ErrorF("drmmode_output_get_modes called\n");
486
487         /* look for an EDID property */
488         for (i = 0; i < koutput->count_props; i++) {
489                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
490                 if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
491                         if (!strcmp(props->name, "EDID")) {
492                                 ErrorF("EDID property found\n");
493                                 if (drmmode_output->edid_blob)
494                                         drmModeFreePropertyBlob(drmmode_output->edid_blob);
495                                 drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
496
497                                 if (!drmmode_output->edid_blob)
498                                         ErrorF("No EDID blob\n");
499                         }
500                         drmModeFreeProperty(props);
501                 }
502         }
503
504         if (drmmode_output->edid_blob)
505                 xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, drmmode_output->edid_blob->data));
506         else
507                 xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, NULL));
508
509         /* modes should already be available */
510         for (i = 0; i < koutput->count_modes; i++) {
511                 Mode = xnfalloc(sizeof(DisplayModeRec));
512
513                 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
514                 Modes = xf86ModesAdd(Modes, Mode);
515
516         }
517         return Modes;
518 }
519
520 static void
521 drmmode_output_destroy(xf86OutputPtr output)
522 {
523         drmmode_output_private_ptr drmmode_output = output->driver_private;
524
525         if (drmmode_output->edid_blob)
526                 drmModeFreePropertyBlob(drmmode_output->edid_blob);
527         drmModeFreeConnector(drmmode_output->mode_output);
528         xfree(drmmode_output);
529         output->driver_private = NULL;
530 }
531
532 static void
533 drmmode_output_dpms(xf86OutputPtr output, int mode)
534 {
535         drmmode_output_private_ptr drmmode_output = output->driver_private;
536         drmModeConnectorPtr koutput = drmmode_output->mode_output;
537         drmmode_ptr drmmode = drmmode_output->drmmode;
538         drmModePropertyPtr props;
539         int i;
540
541         ErrorF("drmmode_output_dpms called with mode %d\n", mode);
542
543         for (i = 0; i < koutput->count_props; i++) {
544                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
545                 if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
546                         if (!strcmp(props->name, "DPMS")) {
547                                 ErrorF("DPMS property found\n");
548                                 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, props->prop_id, mode); 
549                         }
550                         drmModeFreeProperty(props);
551                 }
552         }
553 }
554
555 /*
556  * Output properties.
557  */
558
559 /*
560  * Several scaling modes exist, let the user choose.
561  */
562 #define SCALING_MODE_NAME "SCALING_MODE"
563 static const struct {
564         char *name;
565         int mode;
566 } scaling_mode[] = {
567         { "non-gpu", DRM_MODE_SCALE_NON_GPU },
568         { "fullscreen", DRM_MODE_SCALE_FULLSCREEN },
569         { "aspect", DRM_MODE_SCALE_ASPECT },
570         { "noscale", DRM_MODE_SCALE_NO_SCALE },
571         { NULL, 0xFFFF /* invalid */ }
572 };
573 static Atom scaling_mode_atom;
574
575 #define DITHERING_MODE_NAME "DITHERING"
576 static const struct {
577         char *name;
578         int mode;
579 } dithering_mode[] = {
580         { "off", DRM_MODE_DITHERING_OFF },
581         { "on", DRM_MODE_DITHERING_ON },
582         { NULL, 0xFFFF /* invalid */ }
583 };
584 static Atom dithering_atom;
585
586 int
587 drmmode_scaling_mode_lookup(char *name, int size)
588 {
589         int i;
590
591         /* for when name is zero terminated */
592         if (size < 0)
593                 size = strlen(name);
594
595         for (i = 0; scaling_mode[i].name; i++)
596                 /* We're getting non-terminated strings */
597                 if (strlen(scaling_mode[i].name) >= size &&
598                                 !strncasecmp(name, scaling_mode[i].name, size))
599                         break;
600
601         return scaling_mode[i].mode;
602 }
603
604 int
605 drmmode_dithering_lookup(char *name, int size)
606 {
607         int i;
608
609         /* for when name is zero terminated */
610         if (size < 0)
611                 size = strlen(name);
612
613         for (i = 0; dithering_mode[i].name; i++)
614                 /* We're getting non-terminated strings */
615                 if (strlen(dithering_mode[i].name) >= size &&
616                                 !strncasecmp(name, dithering_mode[i].name, size))
617                         break;
618
619         return dithering_mode[i].mode;
620 }
621
622
623 void
624 drmmode_output_create_resources(xf86OutputPtr output)
625 {
626         ScrnInfoPtr pScrn = output->scrn;
627         int error;
628
629         /*
630          * Setup scaling mode property.
631          */
632         scaling_mode_atom = MakeAtom(SCALING_MODE_NAME, sizeof(SCALING_MODE_NAME) - 1, TRUE);
633
634         error = RRConfigureOutputProperty(output->randr_output,
635                                         scaling_mode_atom, FALSE, FALSE, FALSE,
636                                         0, NULL);
637
638         if (error != 0) {
639                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
640                         "RRConfigureOutputProperty error, %d\n", error);
641         }
642
643         /* property has unknown initial value (for the moment) */
644
645         /*
646          * Setup dithering property.
647          */
648         dithering_atom = MakeAtom(DITHERING_MODE_NAME, sizeof(DITHERING_MODE_NAME) - 1, TRUE);
649
650         error = RRConfigureOutputProperty(output->randr_output,
651                                         dithering_atom, FALSE, FALSE, FALSE,
652                                         0, NULL);
653
654         if (error != 0) {
655                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
656                         "RRConfigureOutputProperty error, %d\n", error);
657         }
658
659         /* property has unknown initial value (for the moment) */
660 }
661
662 Bool
663 drmmode_output_set_property(xf86OutputPtr output, Atom property,
664                                 RRPropertyValuePtr value)
665 {
666         drmmode_output_private_ptr drmmode_output = output->driver_private;
667         drmModeConnectorPtr koutput = drmmode_output->mode_output;
668         drmmode_ptr drmmode = drmmode_output->drmmode;
669         drmModePropertyPtr props;
670         int i, mode, rval = 0;
671
672         if (property == scaling_mode_atom) {
673                 char *name = NULL;
674
675                 if (value->type != XA_STRING || value->format != 8)
676                         return FALSE;
677
678                 name = (char *) value->data;
679
680                 /* Match a string to a scaling mode */
681                 mode = drmmode_scaling_mode_lookup(name, value->size);
682                 if (mode == 0xFFFF)
683                         return FALSE;
684
685                 for (i = 0; i < koutput->count_props; i++) {
686                         props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
687                         if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
688                                 if (!strcmp(props->name, "scaling mode")) {
689                                         ErrorF("scaling mode property found\n");
690                                         rval = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, props->prop_id, mode); 
691                                 }
692                                 drmModeFreeProperty(props);
693                         }
694                 }
695
696                 if (rval)
697                         return FALSE;
698
699                 return TRUE;
700         } else if (property == dithering_atom) {
701                 char *name = NULL;
702
703                 if (value->type != XA_STRING || value->format != 8)
704                         return FALSE;
705
706                 name = (char *) value->data;
707
708                 /* Match a string to a scaling mode */
709                 mode = drmmode_dithering_lookup(name, value->size);
710                 if (mode == 0xFFFF)
711                         return FALSE;
712
713                 for (i = 0; i < koutput->count_props; i++) {
714                         props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
715                         if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
716                                 if (!strcmp(props->name, "dithering")) {
717                                         ErrorF("dithering property found\n");
718                                         rval = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, props->prop_id, mode); 
719                                 }
720                                 drmModeFreeProperty(props);
721                         }
722                 }
723
724                 if (rval)
725                         return FALSE;
726
727                 return TRUE;
728         }
729
730         return FALSE;
731 }
732
733 static const xf86OutputFuncsRec drmmode_output_funcs = {
734         .dpms = drmmode_output_dpms,
735         .detect = drmmode_output_detect,
736         .mode_valid = drmmode_output_mode_valid,
737         .get_modes = drmmode_output_get_modes,
738         .destroy = drmmode_output_destroy,
739         .create_resources = drmmode_output_create_resources,
740         .set_property = drmmode_output_set_property,
741 };
742
743 static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
744                                       SubPixelHorizontalRGB,
745                                       SubPixelHorizontalBGR,
746                                       SubPixelVerticalRGB,
747                                       SubPixelVerticalBGR,
748                                       SubPixelNone };
749
750 struct output_name {
751         const char *name;
752         int count;
753 };
754
755 struct output_name output_names[] = {
756         { "None", 0 },
757         { "VGA", 0 },
758         { "DVI-I", 0 },
759         { "DVI-D", 0 },
760 };
761
762 static void
763 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
764 {
765         xf86OutputPtr output;
766         drmModeConnectorPtr koutput;
767         drmModeEncoderPtr kencoder;
768         drmmode_output_private_ptr drmmode_output;
769         char name[32];
770
771         ErrorF("drmmode_output_init\n");
772
773         koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
774         if (!koutput) {
775                 ErrorF("No connector\n");
776                 return;
777         }
778
779         kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
780         if (!kencoder) {
781                 ErrorF("No encoder\n");
782                 drmModeFreeConnector(koutput);
783                 return;
784         }
785
786         snprintf(name, 32, "%s-%d", output_names[koutput->connector_type].name, output_names[koutput->connector_type].count++);
787
788         output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
789         if (!output) {
790                 drmModeFreeEncoder(kencoder);
791                 drmModeFreeConnector(koutput);
792                 return;
793         }
794
795         drmmode_output = xcalloc(sizeof(drmmode_output_private_rec), 1);
796         if (!drmmode_output) {
797                 xf86OutputDestroy(output);
798                 drmModeFreeConnector(koutput);
799                 drmModeFreeEncoder(kencoder);
800                 return;
801         }
802
803         drmmode_output->output_id = drmmode->mode_res->connectors[num];
804         drmmode_output->mode_output = koutput;
805         drmmode_output->mode_encoder = kencoder;
806         drmmode_output->drmmode = drmmode;
807         output->mm_width = koutput->mmWidth;
808         output->mm_height = koutput->mmHeight;
809
810         output->subpixel_order = subpixel_conv_table[koutput->subpixel];
811         output->driver_private = drmmode_output;
812
813         output->possible_crtcs = kencoder->possible_crtcs;
814         output->possible_clones = kencoder->possible_clones;
815
816         return;
817 }
818
819 void drmmode_set_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height, int pitch, struct nouveau_bo *bo)
820 {
821         int ret;
822
823         ErrorF("drmmode_set_fb is called\n");
824
825         ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
826                            scrn->bitsPerPixel, pitch, bo->map_handle, &drmmode->fb_id);
827
828         if (ret) {
829                 ErrorF("Failed to add fb\n");
830         }
831
832         drmmode->mode_fb = drmModeGetFB(drmmode->fd, drmmode->fb_id);
833         if (!drmmode->mode_fb)
834                 return;
835
836         ErrorF("Add fb id %d %d %d\n", drmmode->fb_id, width, height);
837 }
838
839 #if 0
840 static Bool drmmode_resize_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height)
841 {
842         uint32_t handle;
843         int pitch;
844         int ret;
845
846         ErrorF("current width %d height %d\n", drmmode->mode_fb->width, drmmode->mode_fb->height);
847
848         if (drmmode->mode_fb->width == width && drmmode->mode_fb->height == height)
849                 return TRUE;
850
851         if (!drmmode->create_new_fb)
852                 return FALSE;
853
854         handle = drmmode->create_new_fb(scrn, width, height, &pitch);
855         if (handle == 0)
856                 return FALSE;
857
858         ErrorF("pitch is %d\n", pitch);
859         ret = drmModeReplaceFB(drmmode->fd, drmmode->fb_id, 
860                                width, height,
861                                scrn->depth, scrn->depth, pitch,
862                                handle);
863
864         if (ret)
865                 return FALSE;
866
867         drmModeFreeFB(drmmode->mode_fb);
868         drmmode->mode_fb = drmModeGetFB(drmmode->fd, drmmode->fb_id);
869
870         if (!drmmode->mode_fb)
871                 return FALSE;
872
873         return TRUE;
874 }
875 #endif
876
877 Bool drmmode_pre_init(ScrnInfoPtr pScrn, char *busId, drmmode_ptr drmmode, int cpp)
878 {
879         xf86CrtcConfigPtr xf86_config = NULL;
880         int i, ret;
881
882         int drm_page_size;
883         drm_page_size = getpagesize();
884
885         /* Create a bus Id */
886         /* Low level DRM open */
887         ret = DRIOpenDRMMaster(pScrn, (drm_page_size > SAREA_MAX) ? drm_page_size : SAREA_MAX, busId, "nouveau");
888         if (!ret) {
889                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
890                         "[dri] DRIGetVersion failed to open the DRM\n");
891                 return FALSE;
892         }
893
894         drmmode->fd = DRIMasterFD(pScrn);
895
896         xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
897         xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
898
899         drmmode->cpp = cpp;
900         drmmode->mode_res = drmModeGetResources(drmmode->fd);
901         if (!drmmode->mode_res)
902                 return FALSE;
903
904         xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
905         for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
906                 drmmode_crtc_init(pScrn, drmmode, i);
907
908         for (i = 0; i < drmmode->mode_res->count_connectors; i++)
909                 drmmode_output_init(pScrn, drmmode, i);
910
911         if (!xf86InitialConfiguration(pScrn, FALSE))
912                 return FALSE;
913
914         return TRUE;
915 }
916
917 #endif /* XF86DRM_MODE */