Imported Upstream version 0.3.0
[ubuntu-omap:rsalvetis-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 "drm_fourcc.h"
92 #include "X11/Xatom.h"
93
94 #include <sys/ioctl.h>
95 #include <libudev.h>
96
97 typedef struct {
98         /* hardware cursor: */
99         drmModePlane *ovr;
100         struct omap_bo *bo;
101         uint32_t fb_id;
102         int x, y;
103         int visible;
104 } drmmode_cursor_rec, *drmmode_cursor_ptr;
105
106 typedef struct {
107         int fd;
108         uint32_t fb_id;
109         drmModeResPtr mode_res;
110         int cpp;
111         struct udev_monitor *uevent_monitor;
112         InputHandlerProc uevent_handler;
113         drmmode_cursor_ptr cursor;
114 } drmmode_rec, *drmmode_ptr;
115
116 typedef struct {
117         drmmode_ptr drmmode;
118         drmModeCrtcPtr mode_crtc;
119 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
120
121 typedef struct {
122         drmModePropertyPtr mode_prop;
123         int index; /* Index within the kernel-side property arrays for
124          * this connector. */
125         int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
126          * num_atoms == num_enums + 1 */
127         Atom *atoms;
128 } drmmode_prop_rec, *drmmode_prop_ptr;
129
130 typedef struct {
131         drmmode_ptr drmmode;
132         int output_id;
133         drmModeConnectorPtr mode_output;
134         drmModeEncoderPtr mode_encoder;
135         drmModePropertyBlobPtr edid_blob;
136         int num_props;
137         drmmode_prop_ptr props;
138 } drmmode_output_private_rec, *drmmode_output_private_ptr;
139
140 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
141 void drmmode_remove_fb(ScrnInfoPtr pScrn);
142
143 static drmmode_ptr
144 drmmode_from_scrn(ScrnInfoPtr pScrn)
145 {
146         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
147         drmmode_crtc_private_ptr drmmode_crtc;
148
149         drmmode_crtc = xf86_config->crtc[0]->driver_private;
150         return drmmode_crtc->drmmode;
151 }
152
153 static void
154 drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
155                 DisplayModePtr  mode)
156 {
157         memset(mode, 0, sizeof(DisplayModeRec));
158         mode->status = MODE_OK;
159
160         mode->Clock = kmode->clock;
161
162         mode->HDisplay = kmode->hdisplay;
163         mode->HSyncStart = kmode->hsync_start;
164         mode->HSyncEnd = kmode->hsync_end;
165         mode->HTotal = kmode->htotal;
166         mode->HSkew = kmode->hskew;
167
168         mode->VDisplay = kmode->vdisplay;
169         mode->VSyncStart = kmode->vsync_start;
170         mode->VSyncEnd = kmode->vsync_end;
171         mode->VTotal = kmode->vtotal;
172         mode->VScan = kmode->vscan;
173
174         mode->Flags = kmode->flags; //& FLAG_BITS;
175         mode->name = strdup(kmode->name);
176
177         DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
178
179         if (kmode->type & DRM_MODE_TYPE_DRIVER)
180                 mode->type = M_T_DRIVER;
181         if (kmode->type & DRM_MODE_TYPE_PREFERRED)
182                 mode->type |= M_T_PREFERRED;
183
184         xf86SetModeCrtc (mode, pScrn->adjustFlags);
185 }
186
187 static void
188 drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
189                 DisplayModePtr mode)
190 {
191         memset(kmode, 0, sizeof(*kmode));
192
193         kmode->clock = mode->Clock;
194         kmode->hdisplay = mode->HDisplay;
195         kmode->hsync_start = mode->HSyncStart;
196         kmode->hsync_end = mode->HSyncEnd;
197         kmode->htotal = mode->HTotal;
198         kmode->hskew = mode->HSkew;
199
200         kmode->vdisplay = mode->VDisplay;
201         kmode->vsync_start = mode->VSyncStart;
202         kmode->vsync_end = mode->VSyncEnd;
203         kmode->vtotal = mode->VTotal;
204         kmode->vscan = mode->VScan;
205
206         kmode->flags = mode->Flags; //& FLAG_BITS;
207         if (mode->name)
208                 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
209         kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
210 }
211
212 static void
213 drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
214 {
215         // FIXME - Implement this function
216 }
217
218 static Bool
219 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
220                 Rotation rotation, int x, int y)
221 {
222         ScrnInfoPtr pScrn = crtc->scrn;
223         OMAPPtr pOMAP = OMAPPTR(pScrn);
224         xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
225         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
226         drmmode_ptr drmmode = drmmode_crtc->drmmode;
227         int saved_x, saved_y;
228         Rotation saved_rotation;
229         DisplayModeRec saved_mode;
230         uint32_t *output_ids = NULL;
231         int output_count = 0;
232         int ret = TRUE;
233         int i;
234         int fb_id;
235         drmModeModeInfo kmode;
236
237         TRACE_ENTER();
238
239         /* remove old fb if it exists */
240         drmmode_remove_fb(pScrn);
241
242         if (drmmode->fb_id == 0) {
243                 unsigned int pitch =
244                                 OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel);
245
246                 DEBUG_MSG("create framebuffer: %dx%d",
247                                 pScrn->virtualX, pScrn->virtualY);
248
249                 ret = drmModeAddFB(drmmode->fd,
250                                 pScrn->virtualX, pScrn->virtualY,
251                                 pScrn->depth, pScrn->bitsPerPixel,
252                                 pitch, omap_bo_handle(pOMAP->scanout),
253                                 &drmmode->fb_id);
254                 if (ret < 0) {
255                         // Fixme - improve this error message:
256                         ErrorF("failed to add fb\n");
257                         return FALSE;
258                 }
259         }
260
261         /* Save the current mode in case there's a problem: */
262         saved_mode = crtc->mode;
263         saved_x = crtc->x;
264         saved_y = crtc->y;
265         saved_rotation = crtc->rotation;
266
267         /* Set the new mode: */
268         crtc->mode = *mode;
269         crtc->x = x;
270         crtc->y = y;
271         crtc->rotation = rotation;
272
273         output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
274         if (!output_ids) {
275                 // Fixme - have an error message?
276                 ret = FALSE;
277                 goto done;
278         }
279
280         for (i = 0; i < xf86_config->num_output; i++) {
281                 xf86OutputPtr output = xf86_config->output[i];
282                 drmmode_output_private_ptr drmmode_output;
283
284                 if (output->crtc != crtc)
285                         continue;
286
287                 drmmode_output = output->driver_private;
288                 output_ids[output_count] =
289                                 drmmode_output->mode_output->connector_id;
290                 output_count++;
291         }
292
293         if (!xf86CrtcRotate(crtc))
294                 goto done;
295
296         // Fixme - Intel puts this function here, and Nouveau puts it at the end
297         // of this function -> determine what's best for TI'S OMAP4:
298         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
299                         crtc->gamma_blue, crtc->gamma_size);
300
301         drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
302
303         fb_id = drmmode->fb_id;
304
305         ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
306                         fb_id, x, y, output_ids, output_count, &kmode);
307         if (ret) {
308                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
309                                 "failed to set mode: %s\n", strerror(-ret));
310         } else {
311                 ret = TRUE;
312         }
313
314         // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
315
316         /* Turn on any outputs on this crtc that may have been disabled: */
317         for (i = 0; i < xf86_config->num_output; i++) {
318                 xf86OutputPtr output = xf86_config->output[i];
319
320                 if (output->crtc != crtc)
321                         continue;
322
323                 drmmode_output_dpms(output, DPMSModeOn);
324         }
325
326         // TODO: only call this if we are not using sw cursor.. ie. bad to call this
327         // if we haven't called xf86InitCursor()!!
328         //      if (pScrn->pScreen)
329         //              xf86_reload_cursors(pScrn->pScreen);
330
331 done:
332         if (output_ids) {
333                 free(output_ids);
334         }
335         if (!ret) {
336                 /* If there was a problem, resture the old mode: */
337                 crtc->x = saved_x;
338                 crtc->y = saved_y;
339                 crtc->rotation = saved_rotation;
340                 crtc->mode = saved_mode;
341         }
342
343         TRACE_EXIT();
344         return ret;
345 }
346
347 #define CURSORW  64
348 #define CURSORH  64
349
350 static void
351 drmmode_hide_cursor(xf86CrtcPtr crtc)
352 {
353         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
354         drmmode_ptr drmmode = drmmode_crtc->drmmode;
355         drmmode_cursor_ptr cursor = drmmode->cursor;
356
357         if (!cursor)
358                 return;
359
360         cursor->visible = FALSE;
361
362         /* set plane's fb_id to 0 to disable it */
363         drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
364                         drmmode_crtc->mode_crtc->crtc_id, 0, 0,
365                         0, 0, 0, 0, 0, 0, 0, 0);
366 }
367
368 static void
369 drmmode_show_cursor(xf86CrtcPtr crtc)
370 {
371         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
372         drmmode_ptr drmmode = drmmode_crtc->drmmode;
373         drmmode_cursor_ptr cursor = drmmode->cursor;
374         int crtc_x, crtc_y, src_x, src_y, w, h;
375
376         if (!cursor)
377                 return;
378
379         cursor->visible = TRUE;
380
381         w = CURSORW;
382         h = CURSORH;
383         crtc_x = cursor->x;
384         crtc_y = cursor->y;
385         src_x = 0;
386         src_y = 0;
387
388         if (crtc_x < 0) {
389                 src_x += -crtc_x;
390                 w -= -crtc_x;
391                 crtc_x = 0;
392         }
393
394         if (crtc_y < 0) {
395                 src_y += -crtc_y;
396                 h -= -crtc_y;
397                 crtc_y = 0;
398         }
399
400         if ((crtc_x + w) > crtc->mode.HDisplay) {
401                 w = crtc->mode.HDisplay - crtc_x;
402         }
403
404         if ((crtc_y + h) > crtc->mode.VDisplay) {
405                 h = crtc->mode.VDisplay - crtc_y;
406         }
407
408         /* note src coords (last 4 args) are in Q16 format */
409         drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
410                         drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0,
411                         crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
412 }
413
414 static void
415 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
416 {
417         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
418         drmmode_ptr drmmode = drmmode_crtc->drmmode;
419         drmmode_cursor_ptr cursor = drmmode->cursor;
420
421         if (!cursor)
422                 return;
423
424         cursor->x = x;
425         cursor->y = y;
426
427         if (cursor->visible)
428                 drmmode_show_cursor(crtc);
429 }
430
431 static void
432 drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
433 {
434         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
435         drmmode_ptr drmmode = drmmode_crtc->drmmode;
436         drmmode_cursor_ptr cursor = drmmode->cursor;
437         int visible;
438
439         if (!cursor)
440                 return;
441
442         visible = cursor->visible;
443
444         if (visible)
445                 drmmode_hide_cursor(crtc);
446
447         memcpy(omap_bo_map(cursor->bo), image, omap_bo_size(cursor->bo));
448
449         if (visible)
450                 drmmode_show_cursor(crtc);
451 }
452
453 Bool
454 drmmode_cursor_init(ScreenPtr pScreen)
455 {
456         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
457         OMAPPtr pOMAP = OMAPPTR(pScrn);
458         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
459         drmmode_cursor_ptr cursor;
460         drmModePlaneRes *plane_resources;
461         drmModePlane *ovr;
462
463         /* technically we probably don't have any size limit.. since we
464          * are just using an overlay... but xserver will always create
465          * cursor images in the max size, so don't use width/height values
466          * that are too big
467          */
468         int w = CURSORW, h = CURSORH;
469         uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
470
471         if (drmmode->cursor) {
472                 INFO_MSG("cursor already initialized");
473                 return TRUE;
474         }
475
476         cursor = calloc(1, sizeof(drmmode_cursor_rec));
477
478         /* find an unused plane which can be used as a mouse cursor.  Note
479          * that we cheat a bit, in order to not burn one overlay per crtc,
480          * and only show the mouse cursor on one crtc at a time
481          */
482         plane_resources = drmModeGetPlaneResources(drmmode->fd);
483         if (!plane_resources) {
484                 ERROR_MSG("drmModeGetPlaneResources failed: %s", strerror(errno));
485                 return FALSE;
486         }
487
488         if (plane_resources->count_planes < 1) {
489                 ERROR_MSG("not enough planes for HW cursor");
490                 return FALSE;
491         }
492
493         ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
494         if (!ovr) {
495                 ERROR_MSG("drmModeGetPlane failed: %s\n", strerror(errno));
496                 return FALSE;
497         }
498
499         cursor->ovr = ovr;
500         cursor->bo  = omap_bo_new(pOMAP->dev, w*h*4,
501                         OMAP_BO_SCANOUT | OMAP_BO_WC);
502
503         handles[0] = omap_bo_handle(cursor->bo);
504         pitches[0] = w*4;
505         offsets[0] = 0;
506
507         if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
508                         handles, pitches, offsets, &cursor->fb_id, 0)) {
509                 ERROR_MSG("drmModeAddFB2 failed: %s", strerror(errno));
510                 return FALSE;
511         }
512
513         if (xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
514                 INFO_MSG("HW cursor initialized");
515                 drmmode->cursor = cursor;
516                 return TRUE;
517         }
518
519         // TODO cleanup when things fail..
520         return FALSE;
521 }
522
523 static void
524 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
525                 int size)
526 {
527         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
528         drmmode_ptr drmmode = drmmode_crtc->drmmode;
529         int ret;
530
531         ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
532                         size, red, green, blue);
533         if (ret != 0) {
534                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
535                                 "failed to set gamma: %s\n", strerror(-ret));
536         }
537 }
538
539 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
540                 .dpms = drmmode_crtc_dpms,
541                 .set_mode_major = drmmode_set_mode_major,
542                 .set_cursor_position = drmmode_set_cursor_position,
543                 .show_cursor = drmmode_show_cursor,
544                 .hide_cursor = drmmode_hide_cursor,
545                 .load_cursor_argb = drmmode_load_cursor_argb,
546                 .gamma_set = drmmode_gamma_set,
547 };
548
549
550 static void
551 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
552 {
553         xf86CrtcPtr crtc;
554         drmmode_crtc_private_ptr drmmode_crtc;
555
556         TRACE_ENTER();
557
558         crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
559         if (crtc == NULL)
560                 return;
561
562         drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
563         drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
564                         drmmode->mode_res->crtcs[num]);
565         drmmode_crtc->drmmode = drmmode;
566
567         // FIXME - potentially add code to allocate a HW cursor here.
568
569         crtc->driver_private = drmmode_crtc;
570
571         TRACE_EXIT();
572         return;
573 }
574
575 static xf86OutputStatus
576 drmmode_output_detect(xf86OutputPtr output)
577 {
578         /* go to the hw and retrieve a new output struct */
579         drmmode_output_private_ptr drmmode_output = output->driver_private;
580         drmmode_ptr drmmode = drmmode_output->drmmode;
581         xf86OutputStatus status;
582         drmModeFreeConnector(drmmode_output->mode_output);
583
584         drmmode_output->mode_output =
585                         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
586
587         switch (drmmode_output->mode_output->connection) {
588         case DRM_MODE_CONNECTED:
589                 status = XF86OutputStatusConnected;
590                 break;
591         case DRM_MODE_DISCONNECTED:
592                 status = XF86OutputStatusDisconnected;
593                 break;
594         default:
595         case DRM_MODE_UNKNOWNCONNECTION:
596                 status = XF86OutputStatusUnknown;
597                 break;
598         }
599         return status;
600 }
601
602 static Bool
603 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
604 {
605         if (mode->type & M_T_DEFAULT)
606                 /* Default modes are harmful here. */
607                 return MODE_BAD;
608
609         return MODE_OK;
610 }
611
612 static DisplayModePtr
613 drmmode_output_get_modes(xf86OutputPtr output)
614 {
615         ScrnInfoPtr pScrn = output->scrn;
616         drmmode_output_private_ptr drmmode_output = output->driver_private;
617         drmModeConnectorPtr koutput = drmmode_output->mode_output;
618         drmmode_ptr drmmode = drmmode_output->drmmode;
619         DisplayModePtr Modes = NULL, Mode;
620         drmModePropertyPtr props;
621         xf86MonPtr ddc_mon = NULL;
622         int i;
623
624         /* look for an EDID property */
625         for (i = 0; i < koutput->count_props; i++) {
626                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
627                 if (!props || !(props->flags & DRM_MODE_PROP_BLOB))
628                         continue;
629
630                 if (!strcmp(props->name, "EDID")) {
631                         if (drmmode_output->edid_blob)
632                                 drmModeFreePropertyBlob(drmmode_output->edid_blob);
633                         drmmode_output->edid_blob =
634                                         drmModeGetPropertyBlob(drmmode->fd,
635                                                         koutput->prop_values[i]);
636                 }
637                 drmModeFreeProperty(props);
638         }
639
640         if (drmmode_output->edid_blob)
641                 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
642                                 drmmode_output->edid_blob->data);
643
644         if (ddc_mon) {
645                 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
646                 xf86PrintEDID(ddc_mon);
647                 xf86OutputSetEDID(output, ddc_mon);
648                 xf86SetDDCproperties(pScrn, ddc_mon);
649         }
650
651         DEBUG_MSG("count_modes: %d", koutput->count_modes);
652
653         /* modes should already be available */
654         for (i = 0; i < koutput->count_modes; i++) {
655                 Mode = xnfalloc(sizeof(DisplayModeRec));
656
657                 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
658                                 Mode);
659                 Modes = xf86ModesAdd(Modes, Mode);
660
661         }
662         return Modes;
663 }
664
665 static void
666 drmmode_output_destroy(xf86OutputPtr output)
667 {
668         drmmode_output_private_ptr drmmode_output = output->driver_private;
669         int i;
670
671         if (drmmode_output->edid_blob)
672                 drmModeFreePropertyBlob(drmmode_output->edid_blob);
673         for (i = 0; i < drmmode_output->num_props; i++) {
674                 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
675                 free(drmmode_output->props[i].atoms);
676         }
677         drmModeFreeConnector(drmmode_output->mode_output);
678         free(drmmode_output);
679         output->driver_private = NULL;
680 }
681
682 static void
683 drmmode_output_dpms(xf86OutputPtr output, int mode)
684 {
685         drmmode_output_private_ptr drmmode_output = output->driver_private;
686         drmModeConnectorPtr koutput = drmmode_output->mode_output;
687         drmModePropertyPtr props;
688         drmmode_ptr drmmode = drmmode_output->drmmode;
689         int mode_id = -1, i;
690
691         for (i = 0; i < koutput->count_props; i++) {
692                 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
693                 if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
694                         if (!strcmp(props->name, "DPMS")) {
695                                 mode_id = koutput->props[i];
696                                 drmModeFreeProperty(props);
697                                 break;
698                         }
699                         drmModeFreeProperty(props);
700                 }
701         }
702
703         if (mode_id < 0)
704                 return;
705
706         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
707                         mode_id, mode);
708 }
709
710 static Bool
711 drmmode_property_ignore(drmModePropertyPtr prop)
712 {
713         if (!prop)
714                 return TRUE;
715         /* ignore blob prop */
716         if (prop->flags & DRM_MODE_PROP_BLOB)
717                 return TRUE;
718         /* ignore standard property */
719         if (!strcmp(prop->name, "EDID") ||
720                         !strcmp(prop->name, "DPMS"))
721                 return TRUE;
722
723         return FALSE;
724 }
725
726 static void
727 drmmode_output_create_resources(xf86OutputPtr output)
728 {
729         drmmode_output_private_ptr drmmode_output = output->driver_private;
730         drmModeConnectorPtr mode_output = drmmode_output->mode_output;
731         drmmode_ptr drmmode = drmmode_output->drmmode;
732         drmModePropertyPtr drmmode_prop;
733         uint32_t value;
734         int i, j, err;
735
736         drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
737         if (!drmmode_output->props)
738                 return;
739
740         drmmode_output->num_props = 0;
741         for (i = 0, j = 0; i < mode_output->count_props; i++) {
742                 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
743                 if (drmmode_property_ignore(drmmode_prop)) {
744                         drmModeFreeProperty(drmmode_prop);
745                         continue;
746                 }
747                 drmmode_output->props[j].mode_prop = drmmode_prop;
748                 drmmode_output->props[j].index = i;
749                 drmmode_output->num_props++;
750                 j++;
751         }
752
753         for (i = 0; i < drmmode_output->num_props; i++) {
754                 drmmode_prop_ptr p = &drmmode_output->props[i];
755                 drmmode_prop = p->mode_prop;
756
757                 value = drmmode_output->mode_output->prop_values[p->index];
758
759                 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
760                         INT32 range[2];
761
762                         p->num_atoms = 1;
763                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
764                         if (!p->atoms)
765                                 continue;
766                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
767                         range[0] = drmmode_prop->values[0];
768                         range[1] = drmmode_prop->values[1];
769                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
770                                         FALSE, TRUE,
771                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
772                                                         2, range);
773                         if (err != 0) {
774                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
775                                                 "RRConfigureOutputProperty error, %d\n", err);
776                         }
777                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
778                                         XA_INTEGER, 32, PropModeReplace, 1,
779                                         &value, FALSE, FALSE);
780                         if (err != 0) {
781                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
782                                                 "RRChangeOutputProperty error, %d\n", err);
783                         }
784                 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
785                         p->num_atoms = drmmode_prop->count_enums + 1;
786                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
787                         if (!p->atoms)
788                                 continue;
789                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
790                         for (j = 1; j <= drmmode_prop->count_enums; j++) {
791                                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
792                                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
793                         }
794                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
795                                         FALSE, FALSE,
796                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
797                                                         p->num_atoms - 1, (INT32 *)&p->atoms[1]);
798                         if (err != 0) {
799                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
800                                                 "RRConfigureOutputProperty error, %d\n", err);
801                         }
802                         for (j = 0; j < drmmode_prop->count_enums; j++)
803                                 if (drmmode_prop->enums[j].value == value)
804                                         break;
805                         /* there's always a matching value */
806                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
807                                         XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
808                         if (err != 0) {
809                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
810                                                 "RRChangeOutputProperty error, %d\n", err);
811                         }
812                 }
813         }
814 }
815
816 static Bool
817 drmmode_output_set_property(xf86OutputPtr output, Atom property,
818                 RRPropertyValuePtr value)
819 {
820         drmmode_output_private_ptr drmmode_output = output->driver_private;
821         drmmode_ptr drmmode = drmmode_output->drmmode;
822         int i, ret;
823
824         for (i = 0; i < drmmode_output->num_props; i++) {
825                 drmmode_prop_ptr p = &drmmode_output->props[i];
826
827                 if (p->atoms[0] != property)
828                         continue;
829
830                 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
831                         uint32_t val;
832
833                         if (value->type != XA_INTEGER || value->format != 32 ||
834                                         value->size != 1)
835                                 return FALSE;
836                         val = *(uint32_t *)value->data;
837
838                         ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
839                                         p->mode_prop->prop_id, (uint64_t)val);
840
841                         if (ret)
842                                 return FALSE;
843
844                         return TRUE;
845
846                 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
847                         Atom    atom;
848                         const char      *name;
849                         int             j;
850
851                         if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
852                                 return FALSE;
853                         memcpy(&atom, value->data, 4);
854                         name = NameForAtom(atom);
855
856                         /* search for matching name string, then set its value down */
857                         for (j = 0; j < p->mode_prop->count_enums; j++) {
858                                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
859                                         ret = drmModeConnectorSetProperty(drmmode->fd,
860                                                         drmmode_output->output_id,
861                                                         p->mode_prop->prop_id,
862                                                         p->mode_prop->enums[j].value);
863
864                                         if (ret)
865                                                 return FALSE;
866
867                                         return TRUE;
868                                 }
869                         }
870
871                         return FALSE;
872                 }
873         }
874
875         return TRUE;
876 }
877
878 static Bool
879 drmmode_output_get_property(xf86OutputPtr output, Atom property)
880 {
881
882         drmmode_output_private_ptr drmmode_output = output->driver_private;
883         drmmode_ptr drmmode = drmmode_output->drmmode;
884         uint32_t value;
885         int err, i;
886
887         if (output->scrn->vtSema) {
888                 drmModeFreeConnector(drmmode_output->mode_output);
889                 drmmode_output->mode_output =
890                                 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
891         }
892
893         for (i = 0; i < drmmode_output->num_props; i++) {
894                 drmmode_prop_ptr p = &drmmode_output->props[i];
895                 if (p->atoms[0] != property)
896                         continue;
897
898                 value = drmmode_output->mode_output->prop_values[p->index];
899
900                 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
901                         err = RRChangeOutputProperty(output->randr_output,
902                                         property, XA_INTEGER, 32,
903                                         PropModeReplace, 1, &value,
904                                         FALSE, FALSE);
905
906                         return !err;
907                 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
908                         int             j;
909
910                         /* search for matching name string, then set its value down */
911                         for (j = 0; j < p->mode_prop->count_enums; j++) {
912                                 if (p->mode_prop->enums[j].value == value)
913                                         break;
914                         }
915
916                         err = RRChangeOutputProperty(output->randr_output, property,
917                                         XA_ATOM, 32, PropModeReplace, 1,
918                                         &p->atoms[j+1], FALSE, FALSE);
919
920                         return !err;
921                 }
922         }
923
924         return FALSE;
925 }
926
927 static const xf86OutputFuncsRec drmmode_output_funcs = {
928                 .create_resources = drmmode_output_create_resources,
929                 .dpms = drmmode_output_dpms,
930                 .detect = drmmode_output_detect,
931                 .mode_valid = drmmode_output_mode_valid,
932                 .get_modes = drmmode_output_get_modes,
933                 .set_property = drmmode_output_set_property,
934                 .get_property = drmmode_output_get_property,
935                 .destroy = drmmode_output_destroy
936 };
937
938 // FIXME - Eliminate the following values that aren't accurate for OMAP4:
939 const char *output_names[] = { "None",
940                 "VGA",
941                 "DVI-I",
942                 "DVI-D",
943                 "DVI-A",
944                 "Composite",
945                 "SVIDEO",
946                 "LVDS",
947                 "CTV",
948                 "DIN",
949                 "DP",
950                 "HDMI",
951                 "HDMI",
952                 "TV",
953                 "eDP",
954 };
955 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
956
957 static void
958 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
959 {
960         xf86OutputPtr output;
961         drmModeConnectorPtr koutput;
962         drmModeEncoderPtr kencoder;
963         drmmode_output_private_ptr drmmode_output;
964         char name[32];
965
966         TRACE_ENTER();
967
968         koutput = drmModeGetConnector(drmmode->fd,
969                         drmmode->mode_res->connectors[num]);
970         if (!koutput)
971                 return;
972
973         kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
974         if (!kencoder) {
975                 drmModeFreeConnector(koutput);
976                 return;
977         }
978
979         if (koutput->connector_type >= NUM_OUTPUT_NAMES)
980                 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
981                                 koutput->connector_type_id);
982         else
983                 snprintf(name, 32, "%s-%d",
984                                 output_names[koutput->connector_type],
985                                 koutput->connector_type_id);
986
987         output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
988         if (!output) {
989                 drmModeFreeEncoder(kencoder);
990                 drmModeFreeConnector(koutput);
991                 return;
992         }
993
994         drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
995         if (!drmmode_output) {
996                 xf86OutputDestroy(output);
997                 drmModeFreeConnector(koutput);
998                 drmModeFreeEncoder(kencoder);
999                 return;
1000         }
1001
1002         drmmode_output->output_id = drmmode->mode_res->connectors[num];
1003         drmmode_output->mode_output = koutput;
1004         drmmode_output->mode_encoder = kencoder;
1005         drmmode_output->drmmode = drmmode;
1006
1007         output->mm_width = koutput->mmWidth;
1008         output->mm_height = koutput->mmHeight;
1009         output->driver_private = drmmode_output;
1010
1011         output->possible_crtcs = kencoder->possible_crtcs;
1012         output->possible_clones = kencoder->possible_clones;
1013         output->interlaceAllowed = TRUE;
1014
1015         TRACE_EXIT();
1016         return;
1017 }
1018
1019 static Bool
1020 drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1021 {
1022         OMAPPtr pOMAP = OMAPPTR(pScrn);
1023         ScreenPtr pScreen = pScrn->pScreen;
1024         unsigned int pitch;
1025
1026         TRACE_ENTER();
1027
1028         /* if fb required size has changed, realloc! */
1029
1030         DEBUG_MSG("Resize!  %dx%d", width, height);
1031
1032         pScrn->virtualX = width;
1033         pScrn->virtualY = height;
1034
1035         pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel);
1036
1037         if ((pitch * height) != omap_bo_size(pOMAP->scanout)) {
1038                 /* hmm, should we remove fb here.. we don't want to keep
1039                  * scanning out a deallocated buffer..
1040                  */
1041                 drmmode_remove_fb(pScrn);
1042
1043                 /* delete old scanout buffer */
1044                 omap_bo_del(pOMAP->scanout);
1045
1046                 DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)",
1047                                 width, height, pitch);
1048
1049                 /* allocate new scanout buffer */
1050                 pOMAP->scanout = omap_bo_new(pOMAP->dev, height * pitch,
1051                                 OMAP_BO_SCANOUT | OMAP_BO_WC);
1052                 if (!pOMAP->scanout) {
1053                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1054                                         "Error reallocating scanout buffer\n");
1055                         return FALSE;
1056                 }
1057         }
1058
1059         if (pScreen && pScreen->ModifyPixmapHeader) {
1060                 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1061                 pScreen->ModifyPixmapHeader(rootPixmap,
1062                                 pScrn->virtualX, pScrn->virtualY,
1063                                 pScrn->depth, pScrn->bitsPerPixel, pitch,
1064                                 omap_bo_map(pOMAP->scanout));
1065         }
1066
1067         TRACE_EXIT();
1068         return TRUE;
1069 }
1070
1071 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1072                 drmmode_xf86crtc_resize
1073 };
1074
1075
1076 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1077 {
1078         drmmode_ptr drmmode;
1079         int i;
1080
1081         TRACE_ENTER();
1082
1083         drmmode = calloc(1, sizeof *drmmode);
1084         drmmode->fd = fd;
1085         drmmode->fb_id = 0;
1086
1087         xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
1088
1089
1090         drmmode->cpp = cpp;
1091         drmmode->mode_res = drmModeGetResources(drmmode->fd);
1092         if (!drmmode->mode_res) {
1093                 return FALSE;
1094         } else {
1095                 DEBUG_MSG("Got KMS resources");
1096                 DEBUG_MSG("  %d connectors, %d encoders",
1097                                 drmmode->mode_res->count_connectors,
1098                                 drmmode->mode_res->count_encoders);
1099                 DEBUG_MSG("  %d crtcs, %d fbs",
1100                                 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1101                 DEBUG_MSG("  %dx%d minimum resolution",
1102                                 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1103                 DEBUG_MSG("  %dx%d maximum resolution",
1104                                 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1105         }
1106         xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1107                         drmmode->mode_res->max_height);
1108         for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1109                 drmmode_crtc_init(pScrn, drmmode, i);
1110
1111         for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1112                 drmmode_output_init(pScrn, drmmode, i);
1113
1114         xf86InitialConfiguration(pScrn, TRUE);
1115
1116         TRACE_EXIT();
1117
1118         return TRUE;
1119 }
1120
1121 void
1122 drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags)
1123 {
1124         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1125         xf86OutputPtr output = config->output[config->compat_output];
1126         xf86CrtcPtr crtc = output->crtc;
1127
1128         if (!crtc || !crtc->enabled)
1129                 return;
1130
1131         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1132 }
1133
1134 void
1135 drmmode_remove_fb(ScrnInfoPtr pScrn)
1136 {
1137         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1138         xf86CrtcPtr crtc = NULL;
1139         drmmode_crtc_private_ptr drmmode_crtc;
1140         drmmode_ptr drmmode;
1141
1142         if (config)
1143                 crtc = config->crtc[0];
1144         if (!crtc)
1145                 return;
1146
1147         drmmode_crtc = crtc->driver_private;
1148         drmmode = drmmode_crtc->drmmode;
1149
1150         if (drmmode->fb_id)
1151                 drmModeRmFB(drmmode->fd, drmmode->fb_id);
1152         drmmode->fb_id = 0;
1153 }
1154
1155 /*
1156  * Page Flipping
1157  */
1158
1159 static void
1160 page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
1161                 unsigned int tv_usec, void *user_data)
1162 {
1163         OMAPDRI2SwapComplete(user_data);
1164 }
1165
1166 static drmEventContext event_context = {
1167                 .version = DRM_EVENT_CONTEXT_VERSION,
1168                 .page_flip_handler = page_flip_handler,
1169 };
1170
1171 Bool
1172 drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1173 {
1174         ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1175         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1176         drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1177         drmmode_ptr mode = crtc->drmmode;
1178         int ret, i;
1179
1180         /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1181         for (i = 0; i < config->num_crtc; i++) {
1182                 crtc = config->crtc[i]->driver_private;
1183
1184                 if (!config->crtc[i]->enabled)
1185                         continue;
1186
1187                 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
1188                                 fb_id, DRM_MODE_PAGE_FLIP_EVENT, priv);
1189                 if (ret) {
1190                         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1191                                         "flip queue failed: %s\n", strerror(errno));
1192                         return FALSE;
1193                 }
1194         }
1195
1196         return TRUE;
1197 }
1198
1199 /*
1200  * Hot Plug Event handling:
1201  */
1202
1203 static void
1204 drmmode_handle_uevents(int fd, void *closure)
1205 {
1206         ScrnInfoPtr pScrn = closure;
1207         OMAPPtr pOMAP = OMAPPTR(pScrn);
1208         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1209         struct udev_device *dev;
1210         const char *hotplug;
1211         struct stat s;
1212         dev_t udev_devnum;
1213
1214         dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1215         if (!dev)
1216                 return;
1217
1218         // FIXME - Do we need to keep this code, which Rob originally wrote
1219         // (i.e. up thru the "if" statement)?:
1220
1221         /*
1222          * Check to make sure this event is directed at our
1223          * device (by comparing dev_t values), then make
1224          * sure it's a hotplug event (HOTPLUG=1)
1225          */
1226         udev_devnum = udev_device_get_devnum(dev);
1227         fstat(pOMAP->drmFD, &s);
1228
1229         hotplug = udev_device_get_property_value(dev, "HOTPLUG");
1230
1231         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1232                         memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
1233
1234         if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1235                         hotplug && atoi(hotplug) == 1) {
1236                 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1237         }
1238         udev_device_unref(dev);
1239 }
1240
1241 static void
1242 drmmode_uevent_init(ScrnInfoPtr pScrn)
1243 {
1244         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1245         struct udev *u;
1246         struct udev_monitor *mon;
1247
1248         TRACE_ENTER();
1249
1250         u = udev_new();
1251         if (!u)
1252                 return;
1253         mon = udev_monitor_new_from_netlink(u, "udev");
1254         if (!mon) {
1255                 udev_unref(u);
1256                 return;
1257         }
1258
1259         if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1260                         "drm",
1261                         "drm_minor") < 0 ||
1262                         udev_monitor_enable_receiving(mon) < 0) {
1263                 udev_monitor_unref(mon);
1264                 udev_unref(u);
1265                 return;
1266         }
1267
1268         drmmode->uevent_handler =
1269                         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1270                                         drmmode_handle_uevents, pScrn);
1271
1272         drmmode->uevent_monitor = mon;
1273
1274         TRACE_EXIT();
1275 }
1276
1277 static void
1278 drmmode_uevent_fini(ScrnInfoPtr pScrn)
1279 {
1280         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1281
1282         TRACE_ENTER();
1283
1284         if (drmmode->uevent_handler) {
1285                 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1286                 xf86RemoveGeneralHandler(drmmode->uevent_handler);
1287
1288                 udev_monitor_unref(drmmode->uevent_monitor);
1289                 udev_unref(u);
1290         }
1291
1292         TRACE_EXIT();
1293 }
1294
1295 static void
1296 drmmode_wakeup_handler(pointer data, int err, pointer p)
1297 {
1298         ScrnInfoPtr pScrn = data;
1299         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1300         fd_set *read_mask = p;
1301
1302         if (pScrn == NULL || err < 0)
1303                 return;
1304
1305         if (FD_ISSET(drmmode->fd, read_mask))
1306                 drmHandleEvent(drmmode->fd, &event_context);
1307 }
1308
1309 void
1310 drmmode_wait_for_event(ScrnInfoPtr pScrn)
1311 {
1312         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1313         drmHandleEvent(drmmode->fd, &event_context);
1314 }
1315
1316 void
1317 drmmode_screen_init(ScrnInfoPtr pScrn)
1318 {
1319         drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1320
1321         drmmode_uevent_init(pScrn);
1322
1323         AddGeneralSocket(drmmode->fd);
1324
1325         /* Register a wakeup handler to get informed on DRM events */
1326         RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1327                         drmmode_wakeup_handler, pScrn);
1328 }
1329
1330 void
1331 drmmode_screen_fini(ScrnInfoPtr pScrn)
1332 {
1333         drmmode_uevent_fini(pScrn);
1334 }