drmmode: cleanup/reindent
[gstreamer-omap:xf86-video-omap.git] / src / drmmode_display.c
1 /*
2  * Copyright © 2007 Red Hat, Inc.
3  * Copyright © 2008 Maarten Maathuis
4  * Copyright © 2011 Texas Instruments, Inc
5  *
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *
26  * Authors:
27  *    Dave Airlie <airlied@redhat.com>
28  *    Ian Elliott <ianelliottus@yahoo.com>
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 /* TODO cleanup #includes, remove unnecessary ones */
36
37 #include "xorgVersion.h"
38
39 #include <sys/stat.h>
40
41 #include <string.h>
42 #include <math.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46
47 /* All drivers should typically include these */
48 #include "xf86.h"
49 #include "xf86_OSproc.h"
50 #define PPC_MMIO_IS_BE
51 #include "compiler.h"
52 #include "mipointer.h"
53
54 /* All drivers implementing backing store need this */
55 #include "mibstore.h"
56
57 #include "micmap.h"
58
59 #include "xf86DDC.h"
60
61 #include "vbe.h"
62 #include "xf86RandR12.h"
63 #include "dixstruct.h"
64 #include "scrnintstr.h"
65 #include "fb.h"
66 #include "xf86cmap.h"
67 #include "shadowfb.h"
68
69 #include "xf86xv.h"
70 #include <X11/extensions/Xv.h>
71
72 #include "xf86Cursor.h"
73 #include "xf86DDC.h"
74
75 #include "region.h"
76
77 #include <X11/extensions/randr.h>
78
79 #ifdef HAVE_XEXTPROTO_71
80 #include <X11/extensions/dpmsconst.h>
81 #else
82 #define DPMS_SERVER
83 #include <X11/extensions/dpms.h>
84 #endif
85
86 #include "omap_driver.h"
87
88 #include "xf86Crtc.h"
89
90 #include "xf86drmMode.h"
91 #include "X11/Xatom.h"
92
93 #include <sys/ioctl.h>
94 #include <libudev.h>
95
96 typedef struct {
97         int fd;
98         uint32_t fb_id;
99         drmModeResPtr mode_res;
100         int cpp;
101         struct udev_monitor *uevent_monitor;
102         InputHandlerProc uevent_handler;
103 } drmmode_rec, *drmmode_ptr;
104
105 typedef struct {
106         drmmode_ptr drmmode;
107         drmModeCrtcPtr mode_crtc;
108 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
109
110 typedef struct {
111         drmModePropertyPtr mode_prop;
112         int index; /* Index within the kernel-side property arrays for
113          * this connector. */
114         int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
115          * num_atoms == num_enums + 1 */
116         Atom *atoms;
117 } drmmode_prop_rec, *drmmode_prop_ptr;
118
119 typedef struct {
120         drmmode_ptr drmmode;
121         int output_id;
122         drmModeConnectorPtr mode_output;
123         drmModeEncoderPtr mode_encoder;
124         drmModePropertyBlobPtr edid_blob;
125         int num_props;
126         drmmode_prop_ptr props;
127 } drmmode_output_private_rec, *drmmode_output_private_ptr;
128
129 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
130 void drmmode_remove_fb(ScrnInfoPtr pScrn);
131
132 static void
133 drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
134                 DisplayModePtr  mode)
135 {
136         memset(mode, 0, sizeof(DisplayModeRec));
137         mode->status = MODE_OK;
138
139         mode->Clock = kmode->clock;
140
141         mode->HDisplay = kmode->hdisplay;
142         mode->HSyncStart = kmode->hsync_start;
143         mode->HSyncEnd = kmode->hsync_end;
144         mode->HTotal = kmode->htotal;
145         mode->HSkew = kmode->hskew;
146
147         mode->VDisplay = kmode->vdisplay;
148         mode->VSyncStart = kmode->vsync_start;
149         mode->VSyncEnd = kmode->vsync_end;
150         mode->VTotal = kmode->vtotal;
151         mode->VScan = kmode->vscan;
152
153         mode->Flags = kmode->flags; //& FLAG_BITS;
154         mode->name = strdup(kmode->name);
155
156         DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
157
158         if (kmode->type & DRM_MODE_TYPE_DRIVER)
159                 mode->type = M_T_DRIVER;
160         if (kmode->type & DRM_MODE_TYPE_PREFERRED)
161                 mode->type |= M_T_PREFERRED;
162
163         xf86SetModeCrtc (mode, pScrn->adjustFlags);
164 }
165
166 static void
167 drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
168                 DisplayModePtr mode)
169 {
170         memset(kmode, 0, sizeof(*kmode));
171
172         kmode->clock = mode->Clock;
173         kmode->hdisplay = mode->HDisplay;
174         kmode->hsync_start = mode->HSyncStart;
175         kmode->hsync_end = mode->HSyncEnd;
176         kmode->htotal = mode->HTotal;
177         kmode->hskew = mode->HSkew;
178
179         kmode->vdisplay = mode->VDisplay;
180         kmode->vsync_start = mode->VSyncStart;
181         kmode->vsync_end = mode->VSyncEnd;
182         kmode->vtotal = mode->VTotal;
183         kmode->vscan = mode->VScan;
184
185         kmode->flags = mode->Flags; //& FLAG_BITS;
186         if (mode->name)
187                 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
188         kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
189 }
190
191 static void
192 drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
193 {
194         // FIXME - Implement this function
195 }
196
197 static Bool
198 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
199                 Rotation rotation, int x, int y)
200 {
201         ScrnInfoPtr pScrn = crtc->scrn;
202         OMAPPtr pOMAP = OMAPPTR(pScrn);
203         xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
204         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
205         drmmode_ptr drmmode = drmmode_crtc->drmmode;
206         int saved_x, saved_y;
207         Rotation saved_rotation;
208         DisplayModeRec saved_mode;
209         uint32_t *output_ids = NULL;
210         int output_count = 0;
211         int ret = TRUE;
212         int i;
213         int fb_id;
214         drmModeModeInfo kmode;
215
216         TRACE_ENTER();
217
218         /* remove old fb if it exists */
219         drmmode_remove_fb(pScrn);
220
221         if (drmmode->fb_id == 0) {
222                 unsigned int pitch =
223                                 OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel);
224
225                 DEBUG_MSG("create framebuffer: %dx%d",
226                                 pScrn->virtualX, pScrn->virtualY);
227
228                 ret = drmModeAddFB(drmmode->fd,
229                                 pScrn->virtualX, pScrn->virtualY,
230                                 pScrn->depth, pScrn->bitsPerPixel,
231                                 pitch, omap_bo_handle(pOMAP->scanout),
232                                 &drmmode->fb_id);
233                 if (ret < 0) {
234                         // Fixme - improve this error message:
235                         ErrorF("failed to add fb\n");
236                         return FALSE;
237                 }
238         }
239
240         /* Save the current mode in case there's a problem: */
241         saved_mode = crtc->mode;
242         saved_x = crtc->x;
243         saved_y = crtc->y;
244         saved_rotation = crtc->rotation;
245
246         /* Set the new mode: */
247         crtc->mode = *mode;
248         crtc->x = x;
249         crtc->y = y;
250         crtc->rotation = rotation;
251
252         output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
253         if (!output_ids) {
254                 // Fixme - have an error message?
255                 ret = FALSE;
256                 goto done;
257         }
258
259         for (i = 0; i < xf86_config->num_output; i++) {
260                 xf86OutputPtr output = xf86_config->output[i];
261                 drmmode_output_private_ptr drmmode_output;
262
263                 if (output->crtc != crtc)
264                         continue;
265
266                 drmmode_output = output->driver_private;
267                 output_ids[output_count] =
268                                 drmmode_output->mode_output->connector_id;
269                 output_count++;
270         }
271
272         if (!xf86CrtcRotate(crtc))
273                 goto done;
274
275         // Fixme - Intel puts this function here, and Nouveau puts it at the end
276         // of this function -> determine what's best for TI'S OMAP4:
277         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
278                         crtc->gamma_blue, crtc->gamma_size);
279
280         drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
281
282         fb_id = drmmode->fb_id;
283
284         ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
285                         fb_id, x, y, output_ids, output_count, &kmode);
286         if (ret) {
287                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
288                                 "failed to set mode: %s\n", strerror(-ret));
289         } else {
290                 ret = TRUE;
291         }
292
293         // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
294
295         /* Turn on any outputs on this crtc that may have been disabled: */
296         for (i = 0; i < xf86_config->num_output; i++) {
297                 xf86OutputPtr output = xf86_config->output[i];
298
299                 if (output->crtc != crtc)
300                         continue;
301
302                 drmmode_output_dpms(output, DPMSModeOn);
303         }
304
305         // TODO: only call this if we are not using sw cursor.. ie. bad to call this
306         // if we haven't called xf86InitCursor()!!
307         //      if (pScrn->pScreen)
308         //              xf86_reload_cursors(pScrn->pScreen);
309
310 done:
311         if (output_ids) {
312                 free(output_ids);
313         }
314         if (!ret) {
315                 /* If there was a problem, resture the old mode: */
316                 crtc->x = saved_x;
317                 crtc->y = saved_y;
318                 crtc->rotation = saved_rotation;
319                 crtc->mode = saved_mode;
320         }
321
322         TRACE_EXIT();
323         return ret;
324 }
325
326 static void
327 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
328 {
329 #if 0 // Fixme - address this function when we address HW cursor functionality
330         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
331         drmmode_ptr drmmode = drmmode_crtc->drmmode;
332
333         drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
334 #endif
335 }
336
337 static void
338 drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
339 {
340 #if 0 // Fixme - address this function when we address HW cursor functionality
341 #endif
342 }
343
344 static void
345 drmmode_hide_cursor(xf86CrtcPtr crtc)
346 {
347 #if 0 // Fixme - address this function when we address HW cursor functionality
348         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
349         drmmode_ptr drmmode = drmmode_crtc->drmmode;
350
351         drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
352                         0, 64, 64);
353         drmmode_crtc->cursor_visible = FALSE;
354 #endif
355 }
356
357 static void
358 drmmode_show_cursor(xf86CrtcPtr crtc)
359 {
360 #if 0 // Fixme - address this function when we address HW cursor functionality
361         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
362         drmmode_ptr drmmode = drmmode_crtc->drmmode;
363
364         // Fixme - Do we may need a different data structure for the cursor handle?:
365         drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
366                         drmmode_crtc->cursor->handle, 64, 64);
367
368         drmmode_crtc->cursor_visible = TRUE;
369 #endif
370 }
371
372 static void
373 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
374                 int size)
375 {
376         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
377         drmmode_ptr drmmode = drmmode_crtc->drmmode;
378         int ret;
379
380         ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
381                         size, red, green, blue);
382         if (ret != 0) {
383                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
384                                 "failed to set gamma: %s\n", strerror(-ret));
385         }
386 }
387
388 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
389                 .dpms = drmmode_crtc_dpms,
390                 .set_mode_major = drmmode_set_mode_major,
391                 .set_cursor_position = drmmode_set_cursor_position,
392                 .show_cursor = drmmode_show_cursor,
393                 .hide_cursor = drmmode_hide_cursor,
394                 .load_cursor_argb = drmmode_load_cursor_argb,
395                 .gamma_set = drmmode_gamma_set,
396 };
397
398
399 static void
400 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
401 {
402         xf86CrtcPtr crtc;
403         drmmode_crtc_private_ptr drmmode_crtc;
404
405         TRACE_ENTER();
406
407         crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
408         if (crtc == NULL)
409                 return;
410
411         drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
412         drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
413                         drmmode->mode_res->crtcs[num]);
414         drmmode_crtc->drmmode = drmmode;
415
416         // FIXME - potentially add code to allocate a HW cursor here.
417
418         crtc->driver_private = drmmode_crtc;
419
420         TRACE_EXIT();
421         return;
422 }
423
424 static xf86OutputStatus
425 drmmode_output_detect(xf86OutputPtr output)
426 {
427         /* go to the hw and retrieve a new output struct */
428         drmmode_output_private_ptr drmmode_output = output->driver_private;
429         drmmode_ptr drmmode = drmmode_output->drmmode;
430         xf86OutputStatus status;
431         drmModeFreeConnector(drmmode_output->mode_output);
432
433         drmmode_output->mode_output =
434                         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
435
436         switch (drmmode_output->mode_output->connection) {
437         case DRM_MODE_CONNECTED:
438                 status = XF86OutputStatusConnected;
439                 break;
440         case DRM_MODE_DISCONNECTED:
441                 status = XF86OutputStatusDisconnected;
442                 break;
443         default:
444         case DRM_MODE_UNKNOWNCONNECTION:
445                 status = XF86OutputStatusUnknown;
446                 break;
447         }
448         return status;
449 }
450
451 static Bool
452 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
453 {
454         if (mode->type & M_T_DEFAULT)
455                 /* Default modes are harmful here. */
456                 return MODE_BAD;
457
458         return MODE_OK;
459 }
460
461 static DisplayModePtr
462 drmmode_output_get_modes(xf86OutputPtr output)
463 {
464         ScrnInfoPtr pScrn = output->scrn;
465         drmmode_output_private_ptr drmmode_output = output->driver_private;
466         drmModeConnectorPtr koutput = drmmode_output->mode_output;
467         drmmode_ptr drmmode = drmmode_output->drmmode;
468         DisplayModePtr Modes = NULL, Mode;
469         drmModePropertyPtr props;
470         xf86MonPtr ddc_mon = NULL;
471         int i;
472
473         /* look for an EDID property */
474         for (i = 0; i < koutput->count_props; i++) {
475                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
476                 if (!props || !(props->flags & DRM_MODE_PROP_BLOB))
477                         continue;
478
479                 if (!strcmp(props->name, "EDID")) {
480                         if (drmmode_output->edid_blob)
481                                 drmModeFreePropertyBlob(drmmode_output->edid_blob);
482                         drmmode_output->edid_blob =
483                                         drmModeGetPropertyBlob(drmmode->fd,
484                                                         koutput->prop_values[i]);
485                 }
486                 drmModeFreeProperty(props);
487         }
488
489         if (drmmode_output->edid_blob)
490                 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
491                                 drmmode_output->edid_blob->data);
492
493         if (ddc_mon) {
494                 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
495                 xf86PrintEDID(ddc_mon);
496                 xf86OutputSetEDID(output, ddc_mon);
497                 xf86SetDDCproperties(pScrn, ddc_mon);
498         }
499
500         DEBUG_MSG("count_modes: %d", koutput->count_modes);
501
502         /* modes should already be available */
503         for (i = 0; i < koutput->count_modes; i++) {
504                 Mode = xnfalloc(sizeof(DisplayModeRec));
505
506                 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
507                                 Mode);
508                 Modes = xf86ModesAdd(Modes, Mode);
509
510         }
511         return Modes;
512 }
513
514 static void
515 drmmode_output_destroy(xf86OutputPtr output)
516 {
517         drmmode_output_private_ptr drmmode_output = output->driver_private;
518         int i;
519
520         if (drmmode_output->edid_blob)
521                 drmModeFreePropertyBlob(drmmode_output->edid_blob);
522         for (i = 0; i < drmmode_output->num_props; i++) {
523                 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
524                 free(drmmode_output->props[i].atoms);
525         }
526         drmModeFreeConnector(drmmode_output->mode_output);
527         free(drmmode_output);
528         output->driver_private = NULL;
529 }
530
531 static void
532 drmmode_output_dpms(xf86OutputPtr output, int mode)
533 {
534         drmmode_output_private_ptr drmmode_output = output->driver_private;
535         drmModeConnectorPtr koutput = drmmode_output->mode_output;
536         drmModePropertyPtr props;
537         drmmode_ptr drmmode = drmmode_output->drmmode;
538         int mode_id = -1, i;
539
540         for (i = 0; i < koutput->count_props; i++) {
541                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
542                 if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
543                         if (!strcmp(props->name, "DPMS")) {
544                                 mode_id = koutput->props[i];
545                                 drmModeFreeProperty(props);
546                                 break;
547                         }
548                         drmModeFreeProperty(props);
549                 }
550         }
551
552         if (mode_id < 0)
553                 return;
554
555         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
556                         mode_id, mode);
557 }
558
559 static Bool
560 drmmode_property_ignore(drmModePropertyPtr prop)
561 {
562         if (!prop)
563                 return TRUE;
564         /* ignore blob prop */
565         if (prop->flags & DRM_MODE_PROP_BLOB)
566                 return TRUE;
567         /* ignore standard property */
568         if (!strcmp(prop->name, "EDID") ||
569                         !strcmp(prop->name, "DPMS"))
570                 return TRUE;
571
572         return FALSE;
573 }
574
575 static void
576 drmmode_output_create_resources(xf86OutputPtr output)
577 {
578         drmmode_output_private_ptr drmmode_output = output->driver_private;
579         drmModeConnectorPtr mode_output = drmmode_output->mode_output;
580         drmmode_ptr drmmode = drmmode_output->drmmode;
581         drmModePropertyPtr drmmode_prop;
582         uint32_t value;
583         int i, j, err;
584
585         drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
586         if (!drmmode_output->props)
587                 return;
588
589         drmmode_output->num_props = 0;
590         for (i = 0, j = 0; i < mode_output->count_props; i++) {
591                 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
592                 if (drmmode_property_ignore(drmmode_prop)) {
593                         drmModeFreeProperty(drmmode_prop);
594                         continue;
595                 }
596                 drmmode_output->props[j].mode_prop = drmmode_prop;
597                 drmmode_output->props[j].index = i;
598                 drmmode_output->num_props++;
599                 j++;
600         }
601
602         for (i = 0; i < drmmode_output->num_props; i++) {
603                 drmmode_prop_ptr p = &drmmode_output->props[i];
604                 drmmode_prop = p->mode_prop;
605
606                 value = drmmode_output->mode_output->prop_values[p->index];
607
608                 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
609                         INT32 range[2];
610
611                         p->num_atoms = 1;
612                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
613                         if (!p->atoms)
614                                 continue;
615                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
616                         range[0] = drmmode_prop->values[0];
617                         range[1] = drmmode_prop->values[1];
618                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
619                                         FALSE, TRUE,
620                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
621                                                         2, range);
622                         if (err != 0) {
623                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
624                                                 "RRConfigureOutputProperty error, %d\n", err);
625                         }
626                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
627                                         XA_INTEGER, 32, PropModeReplace, 1,
628                                         &value, FALSE, FALSE);
629                         if (err != 0) {
630                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
631                                                 "RRChangeOutputProperty error, %d\n", err);
632                         }
633                 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
634                         p->num_atoms = drmmode_prop->count_enums + 1;
635                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
636                         if (!p->atoms)
637                                 continue;
638                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
639                         for (j = 1; j <= drmmode_prop->count_enums; j++) {
640                                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
641                                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
642                         }
643                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
644                                         FALSE, FALSE,
645                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
646                                                         p->num_atoms - 1, (INT32 *)&p->atoms[1]);
647                         if (err != 0) {
648                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
649                                                 "RRConfigureOutputProperty error, %d\n", err);
650                         }
651                         for (j = 0; j < drmmode_prop->count_enums; j++)
652                                 if (drmmode_prop->enums[j].value == value)
653                                         break;
654                         /* there's always a matching value */
655                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
656                                         XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
657                         if (err != 0) {
658                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
659                                                 "RRChangeOutputProperty error, %d\n", err);
660                         }
661                 }
662         }
663 }
664
665 static Bool
666 drmmode_output_set_property(xf86OutputPtr output, Atom property,
667                 RRPropertyValuePtr value)
668 {
669         drmmode_output_private_ptr drmmode_output = output->driver_private;
670         drmmode_ptr drmmode = drmmode_output->drmmode;
671         int i, ret;
672
673         for (i = 0; i < drmmode_output->num_props; i++) {
674                 drmmode_prop_ptr p = &drmmode_output->props[i];
675
676                 if (p->atoms[0] != property)
677                         continue;
678
679                 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
680                         uint32_t val;
681
682                         if (value->type != XA_INTEGER || value->format != 32 ||
683                                         value->size != 1)
684                                 return FALSE;
685                         val = *(uint32_t *)value->data;
686
687                         ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
688                                         p->mode_prop->prop_id, (uint64_t)val);
689
690                         if (ret)
691                                 return FALSE;
692
693                         return TRUE;
694
695                 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
696                         Atom    atom;
697                         const char      *name;
698                         int             j;
699
700                         if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
701                                 return FALSE;
702                         memcpy(&atom, value->data, 4);
703                         name = NameForAtom(atom);
704
705                         /* search for matching name string, then set its value down */
706                         for (j = 0; j < p->mode_prop->count_enums; j++) {
707                                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
708                                         ret = drmModeConnectorSetProperty(drmmode->fd,
709                                                         drmmode_output->output_id,
710                                                         p->mode_prop->prop_id,
711                                                         p->mode_prop->enums[j].value);
712
713                                         if (ret)
714                                                 return FALSE;
715
716                                         return TRUE;
717                                 }
718                         }
719
720                         return FALSE;
721                 }
722         }
723
724         return TRUE;
725 }
726
727 static Bool
728 drmmode_output_get_property(xf86OutputPtr output, Atom property)
729 {
730
731         drmmode_output_private_ptr drmmode_output = output->driver_private;
732         drmmode_ptr drmmode = drmmode_output->drmmode;
733         uint32_t value;
734         int err, i;
735
736         if (output->scrn->vtSema) {
737                 drmModeFreeConnector(drmmode_output->mode_output);
738                 drmmode_output->mode_output =
739                                 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
740         }
741
742         for (i = 0; i < drmmode_output->num_props; i++) {
743                 drmmode_prop_ptr p = &drmmode_output->props[i];
744                 if (p->atoms[0] != property)
745                         continue;
746
747                 value = drmmode_output->mode_output->prop_values[p->index];
748
749                 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
750                         err = RRChangeOutputProperty(output->randr_output,
751                                         property, XA_INTEGER, 32,
752                                         PropModeReplace, 1, &value,
753                                         FALSE, FALSE);
754
755                         return !err;
756                 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
757                         int             j;
758
759                         /* search for matching name string, then set its value down */
760                         for (j = 0; j < p->mode_prop->count_enums; j++) {
761                                 if (p->mode_prop->enums[j].value == value)
762                                         break;
763                         }
764
765                         err = RRChangeOutputProperty(output->randr_output, property,
766                                         XA_ATOM, 32, PropModeReplace, 1,
767                                         &p->atoms[j+1], FALSE, FALSE);
768
769                         return !err;
770                 }
771         }
772
773         return FALSE;
774 }
775
776 static const xf86OutputFuncsRec drmmode_output_funcs = {
777                 .create_resources = drmmode_output_create_resources,
778                 .dpms = drmmode_output_dpms,
779                 .detect = drmmode_output_detect,
780                 .mode_valid = drmmode_output_mode_valid,
781                 .get_modes = drmmode_output_get_modes,
782                 .set_property = drmmode_output_set_property,
783                 .get_property = drmmode_output_get_property,
784                 .destroy = drmmode_output_destroy
785 };
786
787 // FIXME - Eliminate the following values that aren't accurate for OMAP4:
788 const char *output_names[] = { "None",
789                 "VGA",
790                 "DVI-I",
791                 "DVI-D",
792                 "DVI-A",
793                 "Composite",
794                 "SVIDEO",
795                 "LVDS",
796                 "CTV",
797                 "DIN",
798                 "DP",
799                 "HDMI",
800                 "HDMI",
801                 "TV",
802                 "eDP",
803 };
804 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
805
806 static void
807 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
808 {
809         xf86OutputPtr output;
810         drmModeConnectorPtr koutput;
811         drmModeEncoderPtr kencoder;
812         drmmode_output_private_ptr drmmode_output;
813         char name[32];
814
815         TRACE_ENTER();
816
817         koutput = drmModeGetConnector(drmmode->fd,
818                         drmmode->mode_res->connectors[num]);
819         if (!koutput)
820                 return;
821
822         kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
823         if (!kencoder) {
824                 drmModeFreeConnector(koutput);
825                 return;
826         }
827
828         if (koutput->connector_type >= NUM_OUTPUT_NAMES)
829                 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
830                                 koutput->connector_type_id);
831         else
832                 snprintf(name, 32, "%s-%d",
833                                 output_names[koutput->connector_type],
834                                 koutput->connector_type_id);
835
836         output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
837         if (!output) {
838                 drmModeFreeEncoder(kencoder);
839                 drmModeFreeConnector(koutput);
840                 return;
841         }
842
843         drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
844         if (!drmmode_output) {
845                 xf86OutputDestroy(output);
846                 drmModeFreeConnector(koutput);
847                 drmModeFreeEncoder(kencoder);
848                 return;
849         }
850
851         drmmode_output->output_id = drmmode->mode_res->connectors[num];
852         drmmode_output->mode_output = koutput;
853         drmmode_output->mode_encoder = kencoder;
854         drmmode_output->drmmode = drmmode;
855
856         output->mm_width = koutput->mmWidth;
857         output->mm_height = koutput->mmHeight;
858         output->driver_private = drmmode_output;
859
860         output->possible_crtcs = kencoder->possible_crtcs;
861         output->possible_clones = kencoder->possible_clones;
862         output->interlaceAllowed = TRUE;
863
864         TRACE_EXIT();
865         return;
866 }
867
868 static Bool
869 drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
870 {
871         OMAPPtr pOMAP = OMAPPTR(pScrn);
872         ScreenPtr pScreen = pScrn->pScreen;
873         unsigned int pitch;
874
875         TRACE_ENTER();
876
877         /* if fb required size has changed, realloc! */
878
879         DEBUG_MSG("Resize!  %dx%d", width, height);
880
881         pScrn->virtualX = width;
882         pScrn->virtualY = height;
883
884         pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel);
885
886         if ((pitch * height) != omap_bo_size(pOMAP->scanout)) {
887                 /* hmm, should we remove fb here.. we don't want to keep
888                  * scanning out a deallocated buffer..
889                  */
890                 drmmode_remove_fb(pScrn);
891
892                 /* delete old scanout buffer */
893                 omap_bo_del(pOMAP->scanout);
894
895                 DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)",
896                                 width, height, pitch);
897
898                 /* allocate new scanout buffer */
899                 pOMAP->scanout = omap_bo_new(pOMAP->dev, height * pitch,
900                                 OMAP_BO_SCANOUT | OMAP_BO_WC);
901                 if (!pOMAP->scanout) {
902                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
903                                         "Error reallocating scanout buffer\n");
904                         return FALSE;
905                 }
906         }
907
908         if (pScreen && pScreen->ModifyPixmapHeader) {
909                 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
910                 pScreen->ModifyPixmapHeader(rootPixmap,
911                                 pScrn->virtualX, pScrn->virtualY,
912                                 pScrn->depth, pScrn->bitsPerPixel, pitch,
913                                 omap_bo_map(pOMAP->scanout));
914         }
915
916         TRACE_EXIT();
917         return TRUE;
918 }
919
920 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
921                 drmmode_xf86crtc_resize
922 };
923
924
925 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
926 {
927         drmmode_ptr drmmode;
928         int i;
929
930         TRACE_ENTER();
931
932         drmmode = calloc(1, sizeof *drmmode);
933         drmmode->fd = fd;
934         drmmode->fb_id = 0;
935
936         xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
937
938
939         drmmode->cpp = cpp;
940         drmmode->mode_res = drmModeGetResources(drmmode->fd);
941         if (!drmmode->mode_res) {
942                 return FALSE;
943         } else {
944                 DEBUG_MSG("Got KMS resources");
945                 DEBUG_MSG("  %d connectors, %d encoders",
946                                 drmmode->mode_res->count_connectors,
947                                 drmmode->mode_res->count_encoders);
948                 DEBUG_MSG("  %d crtcs, %d fbs",
949                                 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
950                 DEBUG_MSG("  %dx%d minimum resolution",
951                                 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
952                 DEBUG_MSG("  %dx%d maximum resolution",
953                                 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
954         }
955         xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
956                         drmmode->mode_res->max_height);
957         for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
958                 drmmode_crtc_init(pScrn, drmmode, i);
959
960         for (i = 0; i < drmmode->mode_res->count_connectors; i++)
961                 drmmode_output_init(pScrn, drmmode, i);
962
963         xf86InitialConfiguration(pScrn, TRUE);
964
965         TRACE_EXIT();
966
967         return TRUE;
968 }
969
970 void
971 drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags)
972 {
973         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
974         xf86OutputPtr output = config->output[config->compat_output];
975         xf86CrtcPtr crtc = output->crtc;
976
977         if (!crtc || !crtc->enabled)
978                 return;
979
980         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
981 }
982
983 void
984 drmmode_remove_fb(ScrnInfoPtr pScrn)
985 {
986         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
987         xf86CrtcPtr crtc = NULL;
988         drmmode_crtc_private_ptr drmmode_crtc;
989         drmmode_ptr drmmode;
990
991         if (config)
992                 crtc = config->crtc[0];
993         if (!crtc)
994                 return;
995
996         drmmode_crtc = crtc->driver_private;
997         drmmode = drmmode_crtc->drmmode;
998
999         if (drmmode->fb_id)
1000                 drmModeRmFB(drmmode->fd, drmmode->fb_id);
1001         drmmode->fb_id = 0;
1002 }
1003
1004 /*
1005  * Page Flipping
1006  */
1007
1008 static void
1009 page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
1010                 unsigned int tv_usec, void *user_data)
1011 {
1012         OMAPDRI2SwapComplete(user_data);
1013 }
1014
1015 static drmEventContext event_context = {
1016                 .version = DRM_EVENT_CONTEXT_VERSION,
1017                 .page_flip_handler = page_flip_handler,
1018 };
1019
1020 Bool
1021 drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1022 {
1023         ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1024         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1025         drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1026         drmmode_ptr mode = crtc->drmmode;
1027         int ret, i;
1028
1029         /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1030         for (i = 0; i < config->num_crtc; i++) {
1031                 crtc = config->crtc[i]->driver_private;
1032
1033                 if (!config->crtc[i]->enabled)
1034                         continue;
1035
1036                 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
1037                                 fb_id, DRM_MODE_PAGE_FLIP_EVENT, priv);
1038                 if (ret) {
1039                         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1040                                         "flip queue failed: %s\n", strerror(errno));
1041                         return FALSE;
1042                 }
1043         }
1044
1045         return TRUE;
1046 }
1047
1048 /*
1049  * Hot Plug Event handling:
1050  */
1051
1052 static drmmode_ptr
1053 drmmode_from_scrn(ScrnInfoPtr pScrn)
1054 {
1055         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1056         drmmode_crtc_private_ptr drmmode_crtc;
1057
1058         drmmode_crtc = xf86_config->crtc[0]->driver_private;
1059         return drmmode_crtc->drmmode;
1060 }
1061
1062 static void
1063 drmmode_handle_uevents(int fd, void *closure)
1064 {
1065         ScrnInfoPtr pScrn = closure;
1066         OMAPPtr pOMAP = OMAPPTR(pScrn);
1067         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1068         struct udev_device *dev;
1069         const char *hotplug;
1070         struct stat s;
1071         dev_t udev_devnum;
1072
1073         dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1074         if (!dev)
1075                 return;
1076
1077         // FIXME - Do we need to keep this code, which Rob originally wrote
1078         // (i.e. up thru the "if" statement)?:
1079
1080         /*
1081          * Check to make sure this event is directed at our
1082          * device (by comparing dev_t values), then make
1083          * sure it's a hotplug event (HOTPLUG=1)
1084          */
1085         udev_devnum = udev_device_get_devnum(dev);
1086         fstat(pOMAP->drmFD, &s);
1087
1088         hotplug = udev_device_get_property_value(dev, "HOTPLUG");
1089
1090         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1091                         memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
1092
1093         if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1094                         hotplug && atoi(hotplug) == 1) {
1095                 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1096         }
1097         udev_device_unref(dev);
1098 }
1099
1100 static void
1101 drmmode_uevent_init(ScrnInfoPtr pScrn)
1102 {
1103         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1104         struct udev *u;
1105         struct udev_monitor *mon;
1106
1107         TRACE_ENTER();
1108
1109         u = udev_new();
1110         if (!u)
1111                 return;
1112         mon = udev_monitor_new_from_netlink(u, "udev");
1113         if (!mon) {
1114                 udev_unref(u);
1115                 return;
1116         }
1117
1118         if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1119                         "drm",
1120                         "drm_minor") < 0 ||
1121                         udev_monitor_enable_receiving(mon) < 0) {
1122                 udev_monitor_unref(mon);
1123                 udev_unref(u);
1124                 return;
1125         }
1126
1127         drmmode->uevent_handler =
1128                         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1129                                         drmmode_handle_uevents, pScrn);
1130
1131         drmmode->uevent_monitor = mon;
1132
1133         TRACE_EXIT();
1134 }
1135
1136 static void
1137 drmmode_uevent_fini(ScrnInfoPtr pScrn)
1138 {
1139         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1140
1141         TRACE_ENTER();
1142
1143         if (drmmode->uevent_handler) {
1144                 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1145                 xf86RemoveGeneralHandler(drmmode->uevent_handler);
1146
1147                 udev_monitor_unref(drmmode->uevent_monitor);
1148                 udev_unref(u);
1149         }
1150
1151         TRACE_EXIT();
1152 }
1153
1154 static void
1155 drmmode_wakeup_handler(pointer data, int err, pointer p)
1156 {
1157         ScrnInfoPtr scrn = data;
1158         drmmode_ptr drmmode = drmmode_from_scrn(scrn);
1159         fd_set *read_mask = p;
1160
1161         if (scrn == NULL || err < 0)
1162                 return;
1163
1164         if (FD_ISSET(drmmode->fd, read_mask))
1165                 drmHandleEvent(drmmode->fd, &event_context);
1166 }
1167
1168 void
1169 drmmode_screen_init(ScrnInfoPtr pScrn)
1170 {
1171         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1172
1173         drmmode_uevent_init(pScrn);
1174
1175         AddGeneralSocket(drmmode->fd);
1176
1177         /* Register a wakeup handler to get informed on DRM events */
1178         RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1179                         drmmode_wakeup_handler, pScrn);
1180 }
1181
1182 void
1183 drmmode_screen_fini(ScrnInfoPtr pScrn)
1184 {
1185         drmmode_uevent_fini(pScrn);
1186 }