Add raw modeline support.
[profile/ivi/weston.git] / src / compositor-drm.c
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #define _GNU_SOURCE
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <linux/input.h>
32 #include <assert.h>
33
34 #include <xf86drm.h>
35 #include <xf86drmMode.h>
36 #include <drm_fourcc.h>
37
38 #include <gbm.h>
39 #include <libbacklight.h>
40
41 #include "compositor.h"
42 #include "evdev.h"
43 #include "launcher-util.h"
44 #include "log.h"
45
46 static int option_current_mode = 0;
47 static char *output_name;
48 static char *output_mode;
49 static struct wl_list configured_output_list;
50
51 enum output_config {
52         OUTPUT_CONFIG_INVALID = 0,
53         OUTPUT_CONFIG_OFF,
54         OUTPUT_CONFIG_PREFERRED,
55         OUTPUT_CONFIG_CURRENT,
56         OUTPUT_CONFIG_MODE,
57         OUTPUT_CONFIG_MODELINE
58 };
59
60 struct drm_configured_output {
61         char *name;
62         char *mode;
63         int32_t width, height;
64         drmModeModeInfo crtc_mode;
65         enum output_config config;
66         struct wl_list link;
67 };
68
69 enum {
70         WESTON_PLANE_DRM_CURSOR =       0x100,
71         WESTON_PLANE_DRM_PLANE =        0x101,
72         WESTON_PLANE_DRM_FB =           0x102
73 };
74
75 struct drm_compositor {
76         struct weston_compositor base;
77
78         struct udev *udev;
79         struct wl_event_source *drm_source;
80
81         struct udev_monitor *udev_monitor;
82         struct wl_event_source *udev_drm_source;
83
84         struct {
85                 int id;
86                 int fd;
87         } drm;
88         struct gbm_device *gbm;
89         uint32_t *crtcs;
90         int num_crtcs;
91         uint32_t crtc_allocator;
92         uint32_t connector_allocator;
93         struct tty *tty;
94
95         struct gbm_surface *dummy_surface;
96         EGLSurface dummy_egl_surface;
97
98         struct wl_list sprite_list;
99         int sprites_are_broken;
100
101         uint32_t prev_state;
102 };
103
104 struct drm_mode {
105         struct weston_mode base;
106         drmModeModeInfo mode_info;
107 };
108
109 struct drm_output;
110
111 struct drm_fb {
112         struct gbm_bo *bo;
113         struct drm_output *output;
114         uint32_t fb_id;
115         int is_client_buffer;
116         struct wl_buffer *buffer;
117         struct wl_listener buffer_destroy_listener;
118 };
119
120 struct drm_output {
121         struct weston_output   base;
122
123         char *name;
124         uint32_t crtc_id;
125         uint32_t connector_id;
126         drmModeCrtcPtr original_crtc;
127
128         int vblank_pending;
129         int page_flip_pending;
130
131         struct gbm_surface *surface;
132         struct gbm_bo *cursor_bo[2];
133         int current_cursor, cursor_free, cursor_x, cursor_y;
134         EGLSurface egl_surface;
135         struct drm_fb *current, *next;
136         struct backlight *backlight;
137 };
138
139 /*
140  * An output has a primary display plane plus zero or more sprites for
141  * blending display contents.
142  */
143 struct drm_sprite {
144         struct wl_list link;
145
146         uint32_t fb_id;
147         uint32_t pending_fb_id;
148         struct weston_surface *surface;
149         struct weston_surface *pending_surface;
150
151         struct drm_output *output;
152
153         struct drm_compositor *compositor;
154
155         struct wl_listener destroy_listener;
156         struct wl_listener pending_destroy_listener;
157
158         uint32_t possible_crtcs;
159         uint32_t plane_id;
160         uint32_t count_formats;
161
162         int32_t src_x, src_y;
163         uint32_t src_w, src_h;
164         uint32_t dest_x, dest_y;
165         uint32_t dest_w, dest_h;
166
167         uint32_t formats[];
168 };
169
170 static int
171 drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
172 {
173         struct weston_compositor *ec = output_base->compositor;
174         struct drm_compositor *c =(struct drm_compositor *) ec;
175         struct drm_output *output = (struct drm_output *) output_base;
176         int crtc;
177
178         for (crtc = 0; crtc < c->num_crtcs; crtc++) {
179                 if (c->crtcs[crtc] != output->crtc_id)
180                         continue;
181
182                 if (supported & (1 << crtc))
183                         return -1;
184         }
185
186         return 0;
187 }
188
189 static void
190 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
191 {
192         struct drm_fb *fb = data;
193         struct gbm_device *gbm = gbm_bo_get_device(bo);
194
195         if (fb->fb_id)
196                 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
197
198         if (fb->buffer) {
199                 weston_buffer_post_release(fb->buffer);
200                 wl_list_remove(&fb->buffer_destroy_listener.link);
201         }
202
203         free(data);
204 }
205
206 static struct drm_fb *
207 drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
208 {
209         struct drm_fb *fb = gbm_bo_get_user_data(bo);
210         struct drm_compositor *compositor =
211                 (struct drm_compositor *) output->base.compositor;
212         uint32_t width, height, stride, handle;
213         int ret;
214
215         if (fb)
216                 return fb;
217
218         fb = malloc(sizeof *fb);
219
220         fb->bo = bo;
221         fb->output = output;
222         fb->is_client_buffer = 0;
223         fb->buffer = NULL;
224
225         width = gbm_bo_get_width(bo);
226         height = gbm_bo_get_height(bo);
227         stride = gbm_bo_get_stride(bo);
228         handle = gbm_bo_get_handle(bo).u32;
229
230         ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
231                            stride, handle, &fb->fb_id);
232         if (ret) {
233                 weston_log("failed to create kms fb: %m\n");
234                 free(fb);
235                 return NULL;
236         }
237
238         gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
239
240         return fb;
241 }
242
243 static void
244 fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
245 {
246         struct drm_fb *fb = container_of(listener, struct drm_fb,
247                                          buffer_destroy_listener);
248
249         fb->buffer = NULL;
250
251         if (fb == fb->output->next ||
252             (fb == fb->output->current && !fb->output->next))
253                 weston_output_schedule_repaint(&fb->output->base);
254 }
255
256 static int
257 drm_output_prepare_scanout_surface(struct weston_output *_output,
258                                    struct weston_surface *es)
259 {
260         struct drm_output *output = (struct drm_output *) _output;
261         struct drm_compositor *c =
262                 (struct drm_compositor *) output->base.compositor;
263         struct gbm_bo *bo;
264
265         if (es->geometry.x != output->base.x ||
266             es->geometry.y != output->base.y ||
267             es->geometry.width != output->base.current->width ||
268             es->geometry.height != output->base.current->height ||
269             es->transform.enabled ||
270             es->buffer == NULL)
271                 return -1;
272
273         bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
274                            es->buffer, GBM_BO_USE_SCANOUT);
275
276         /* Need to verify output->region contained in surface opaque
277          * region.  Or maybe just that format doesn't have alpha.
278          * For now, scanout only if format is XRGB8888. */
279         if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
280                 gbm_bo_destroy(bo);
281                 return -1;
282         }
283
284         output->next = drm_fb_get_from_bo(bo, output);
285         if (!output->next) {
286                 gbm_bo_destroy(bo);
287                 return -1;
288         }
289
290         output->next->is_client_buffer = 1;
291         output->next->buffer = es->buffer;
292         output->next->buffer->busy_count++;
293         output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
294
295         wl_signal_add(&output->next->buffer->resource.destroy_signal,
296                       &output->next->buffer_destroy_listener);
297
298         es->plane = WESTON_PLANE_DRM_FB;
299
300         return 0;
301 }
302
303 static void
304 drm_output_render(struct drm_output *output, pixman_region32_t *damage)
305 {
306         struct drm_compositor *compositor =
307                 (struct drm_compositor *) output->base.compositor;
308         struct weston_surface *surface;
309         struct gbm_bo *bo;
310
311         if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
312                             output->egl_surface,
313                             compositor->base.egl_context)) {
314                 weston_log("failed to make current\n");
315                 return;
316         }
317
318         wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
319                 if (surface->plane == WESTON_PLANE_PRIMARY)
320                         weston_surface_draw(surface, &output->base, damage);
321
322         wl_signal_emit(&output->base.frame_signal, output);
323
324         eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
325         bo = gbm_surface_lock_front_buffer(output->surface);
326         if (!bo) {
327                 weston_log("failed to lock front buffer: %m\n");
328                 return;
329         }
330
331         output->next = drm_fb_get_from_bo(bo, output);
332         if (!output->next) {
333                 weston_log("failed to get drm_fb for bo\n");
334                 gbm_surface_release_buffer(output->surface, bo);
335                 return;
336         }
337 }
338
339 static void
340 drm_output_repaint(struct weston_output *output_base,
341                    pixman_region32_t *damage)
342 {
343         struct drm_output *output = (struct drm_output *) output_base;
344         struct drm_compositor *compositor =
345                 (struct drm_compositor *) output->base.compositor;
346         struct drm_sprite *s;
347         struct drm_mode *mode;
348         int ret = 0;
349
350         if (!output->next)
351                 drm_output_render(output, damage);
352         if (!output->next)
353                 return;
354
355         mode = container_of(output->base.current, struct drm_mode, base);
356         if (!output->current) {
357                 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
358                                      output->next->fb_id, 0, 0,
359                                      &output->connector_id, 1,
360                                      &mode->mode_info);
361                 if (ret) {
362                         weston_log("set mode failed: %m\n");
363                         return;
364                 }
365         }
366
367         if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
368                             output->next->fb_id,
369                             DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
370                 weston_log("queueing pageflip failed: %m\n");
371                 return;
372         }
373
374         output->page_flip_pending = 1;
375
376         /*
377          * Now, update all the sprite surfaces
378          */
379         wl_list_for_each(s, &compositor->sprite_list, link) {
380                 uint32_t flags = 0;
381                 drmVBlank vbl = {
382                         .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
383                         .request.sequence = 1,
384                 };
385
386                 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
387                         continue;
388
389                 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
390                                       output->crtc_id, s->pending_fb_id, flags,
391                                       s->dest_x, s->dest_y,
392                                       s->dest_w, s->dest_h,
393                                       s->src_x, s->src_y,
394                                       s->src_w, s->src_h);
395                 if (ret)
396                         weston_log("setplane failed: %d: %s\n",
397                                 ret, strerror(errno));
398
399                 /*
400                  * Queue a vblank signal so we know when the surface
401                  * becomes active on the display or has been replaced.
402                  */
403                 vbl.request.signal = (unsigned long)s;
404                 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
405                 if (ret) {
406                         weston_log("vblank event request failed: %d: %s\n",
407                                 ret, strerror(errno));
408                 }
409
410                 s->output = output;
411                 output->vblank_pending = 1;
412         }
413
414         return;
415 }
416
417 static void
418 vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
419                void *data)
420 {
421         struct drm_sprite *s = (struct drm_sprite *)data;
422         struct drm_compositor *c = s->compositor;
423         struct drm_output *output = s->output;
424         uint32_t msecs;
425
426         output->vblank_pending = 0;
427
428         if (s->surface) {
429                 weston_buffer_post_release(s->surface->buffer);
430                 wl_list_remove(&s->destroy_listener.link);
431                 s->surface = NULL;
432                 drmModeRmFB(c->drm.fd, s->fb_id);
433                 s->fb_id = 0;
434         }
435
436         if (s->pending_surface) {
437                 wl_list_remove(&s->pending_destroy_listener.link);
438                 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
439                               &s->destroy_listener);
440                 s->surface = s->pending_surface;
441                 s->pending_surface = NULL;
442                 s->fb_id = s->pending_fb_id;
443                 s->pending_fb_id = 0;
444         }
445
446         if (!output->page_flip_pending) {
447                 msecs = sec * 1000 + usec / 1000;
448                 weston_output_finish_frame(&output->base, msecs);
449         }
450 }
451
452 static void
453 page_flip_handler(int fd, unsigned int frame,
454                   unsigned int sec, unsigned int usec, void *data)
455 {
456         struct drm_output *output = (struct drm_output *) data;
457         uint32_t msecs;
458
459         output->page_flip_pending = 0;
460
461         if (output->current) {
462                 if (output->current->is_client_buffer)
463                         gbm_bo_destroy(output->current->bo);
464                 else
465                         gbm_surface_release_buffer(output->surface,
466                                                    output->current->bo);
467         }
468
469         output->current = output->next;
470         output->next = NULL;
471
472         if (!output->vblank_pending) {
473                 msecs = sec * 1000 + usec / 1000;
474                 weston_output_finish_frame(&output->base, msecs);
475         }
476 }
477
478 static int
479 drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
480 {
481         uint32_t i;
482
483         for (i = 0; i < s->count_formats; i++)
484                 if (s->formats[i] == format)
485                         return 1;
486
487         return 0;
488 }
489
490 static int
491 drm_surface_transform_supported(struct weston_surface *es)
492 {
493         struct weston_matrix *matrix = &es->transform.matrix;
494         int i;
495
496         if (!es->transform.enabled)
497                 return 1;
498
499         for (i = 0; i < 16; i++) {
500                 switch (i) {
501                 case 10:
502                 case 15:
503                         if (matrix->d[i] != 1.0)
504                                 return 0;
505                         break;
506                 case 0:
507                 case 5:
508                 case 12:
509                 case 13:
510                         break;
511                 default:
512                         if (matrix->d[i] != 0.0)
513                                 return 0;
514                         break;
515                 }
516         }
517
518         return 1;
519 }
520
521 static void
522 drm_disable_unused_sprites(struct weston_output *output_base)
523 {
524         struct weston_compositor *ec = output_base->compositor;
525         struct drm_compositor *c =(struct drm_compositor *) ec;
526         struct drm_output *output = (struct drm_output *) output_base;
527         struct drm_sprite *s;
528         int ret;
529
530         wl_list_for_each(s, &c->sprite_list, link) {
531                 if (s->pending_fb_id)
532                         continue;
533
534                 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
535                                       output->crtc_id, 0, 0,
536                                       0, 0, 0, 0, 0, 0, 0, 0);
537                 if (ret)
538                         weston_log("failed to disable plane: %d: %s\n",
539                                 ret, strerror(errno));
540                 drmModeRmFB(c->drm.fd, s->fb_id);
541
542                 if (s->surface) {
543                         s->surface = NULL;
544                         wl_list_remove(&s->destroy_listener.link);
545                 }
546
547                 assert(!s->pending_surface);
548                 s->fb_id = 0;
549                 s->pending_fb_id = 0;
550         }
551 }
552
553 /*
554  * This function must take care to damage any previously assigned surface
555  * if the sprite ends up binding to a different surface than in the
556  * previous frame.
557  */
558 static int
559 drm_output_prepare_overlay_surface(struct weston_output *output_base,
560                                    struct weston_surface *es)
561 {
562         struct weston_compositor *ec = output_base->compositor;
563         struct drm_compositor *c =(struct drm_compositor *) ec;
564         struct drm_sprite *s;
565         int found = 0;
566         EGLint handle, stride;
567         struct gbm_bo *bo;
568         uint32_t fb_id = 0;
569         uint32_t handles[4], pitches[4], offsets[4];
570         int ret = 0;
571         pixman_region32_t dest_rect, src_rect;
572         pixman_box32_t *box;
573         uint32_t format;
574         wl_fixed_t sx1, sy1, sx2, sy2;
575
576         if (c->sprites_are_broken)
577                 return -1;
578
579         if (es->output_mask != (1u << output_base->id))
580                 return -1;
581
582         if (es->buffer == NULL)
583                 return -1;
584
585         if (!drm_surface_transform_supported(es))
586                 return -1;
587
588         wl_list_for_each(s, &c->sprite_list, link) {
589                 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
590                         continue;
591
592                 if (!s->pending_fb_id) {
593                         found = 1;
594                         break;
595                 }
596         }
597
598         /* No sprites available */
599         if (!found)
600                 return -1;
601
602         bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
603                            es->buffer, GBM_BO_USE_SCANOUT);
604         if (!bo)
605                 return -1;
606
607         format = gbm_bo_get_format(bo);
608         handle = gbm_bo_get_handle(bo).s32;
609         stride = gbm_bo_get_stride(bo);
610
611         gbm_bo_destroy(bo);
612
613         if (!drm_surface_format_supported(s, format))
614                 return -1;
615
616         if (!handle)
617                 return -1;
618
619         handles[0] = handle;
620         pitches[0] = stride;
621         offsets[0] = 0;
622
623         ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
624                             format, handles, pitches, offsets,
625                             &fb_id, 0);
626         if (ret) {
627                 weston_log("addfb2 failed: %d\n", ret);
628                 c->sprites_are_broken = 1;
629                 return -1;
630         }
631
632         s->pending_fb_id = fb_id;
633         s->pending_surface = es;
634         es->buffer->busy_count++;
635
636         /*
637          * Calculate the source & dest rects properly based on actual
638          * postion (note the caller has called weston_surface_update_transform()
639          * for us already).
640          */
641         pixman_region32_init(&dest_rect);
642         pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
643                                   &output_base->region);
644         pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
645         box = pixman_region32_extents(&dest_rect);
646         s->dest_x = box->x1;
647         s->dest_y = box->y1;
648         s->dest_w = box->x2 - box->x1;
649         s->dest_h = box->y2 - box->y1;
650         pixman_region32_fini(&dest_rect);
651
652         pixman_region32_init(&src_rect);
653         pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
654                                   &output_base->region);
655         box = pixman_region32_extents(&src_rect);
656
657         weston_surface_from_global_fixed(es,
658                                          wl_fixed_from_int(box->x1),
659                                          wl_fixed_from_int(box->y1),
660                                          &sx1, &sy1);
661         weston_surface_from_global_fixed(es,
662                                          wl_fixed_from_int(box->x2),
663                                          wl_fixed_from_int(box->y2),
664                                          &sx2, &sy2);
665
666         if (sx1 < 0)
667                 sx1 = 0;
668         if (sy1 < 0)
669                 sy1 = 0;
670         if (sx2 > wl_fixed_from_int(es->geometry.width))
671                 sx2 = wl_fixed_from_int(es->geometry.width);
672         if (sy2 > wl_fixed_from_int(es->geometry.height))
673                 sy2 = wl_fixed_from_int(es->geometry.height);
674
675         s->src_x = sx1 << 8;
676         s->src_y = sy1 << 8;
677         s->src_w = (sx2 - sx1) << 8;
678         s->src_h = (sy2 - sy1) << 8;
679         pixman_region32_fini(&src_rect);
680
681         es->plane = WESTON_PLANE_DRM_PLANE;
682
683         wl_signal_add(&es->buffer->resource.destroy_signal,
684                       &s->pending_destroy_listener);
685
686         return 0;
687 }
688
689 static void
690 drm_output_set_cursor(struct weston_output *output_base,
691                       struct weston_surface *es)
692 {
693         struct drm_output *output = (struct drm_output *) output_base;
694         struct drm_compositor *c =
695                 (struct drm_compositor *) output->base.compositor;
696         EGLint handle, stride;
697         struct gbm_bo *bo;
698         uint32_t buf[64 * 64];
699         unsigned char *s;
700         int i, x, y;
701
702         if (!output->cursor_free)
703                 return;
704         if (es->output_mask != (1u << output_base->id))
705                 return;
706         if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
707             es->geometry.width > 64 || es->geometry.height > 64)
708                 return;
709
710         if (es->buffer && pixman_region32_not_empty(&es->damage)) {
711                 output->current_cursor ^= 1;
712                 bo = output->cursor_bo[output->current_cursor];
713                 memset(buf, 0, sizeof buf);
714                 stride = wl_shm_buffer_get_stride(es->buffer);
715                 s = wl_shm_buffer_get_data(es->buffer);
716                 for (i = 0; i < es->geometry.height; i++)
717                         memcpy(buf + i * 64, s + i * stride,
718                                es->geometry.width * 4);
719
720                 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
721                         return;
722
723                 handle = gbm_bo_get_handle(bo).s32;
724                 if (drmModeSetCursor(c->drm.fd,
725                                      output->crtc_id, handle, 64, 64)) {
726                         weston_log("failed to set cursor: %n\n");
727                         return;
728                 }
729         }
730
731         x = es->geometry.x - output->base.x;
732         y = es->geometry.y - output->base.y;
733         if (output->cursor_x != x || output->cursor_y != y) {
734                 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
735                         weston_log("failed to move cursor: %m\n");
736                         return;
737                 }
738                 output->cursor_x = x;
739                 output->cursor_y = y;
740         }
741
742         es->plane = WESTON_PLANE_DRM_CURSOR;
743         output->cursor_free = 0;
744 }
745
746 static void
747 drm_assign_planes(struct weston_output *output)
748 {
749         struct drm_compositor *c =
750                 (struct drm_compositor *) output->compositor;
751         struct drm_output *drm_output = (struct drm_output *) output;
752         struct weston_surface *es, *next;
753         pixman_region32_t overlap, surface_overlap;
754         int prev_plane;
755
756         /*
757          * Find a surface for each sprite in the output using some heuristics:
758          * 1) size
759          * 2) frequency of update
760          * 3) opacity (though some hw might support alpha blending)
761          * 4) clipping (this can be fixed with color keys)
762          *
763          * The idea is to save on blitting since this should save power.
764          * If we can get a large video surface on the sprite for example,
765          * the main display surface may not need to update at all, and
766          * the client buffer can be used directly for the sprite surface
767          * as we do for flipping full screen surfaces.
768          */
769         pixman_region32_init(&overlap);
770         drm_output->cursor_free = 1;
771         wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
772                 pixman_region32_init(&surface_overlap);
773                 pixman_region32_intersect(&surface_overlap, &overlap,
774                                           &es->transform.boundingbox);
775
776                 prev_plane = es->plane;
777                 es->plane = WESTON_PLANE_PRIMARY;
778                 if (pixman_region32_not_empty(&surface_overlap))
779                         goto bail;
780
781                 if (es->plane == WESTON_PLANE_PRIMARY)
782                         drm_output_set_cursor(output, es);
783                 if (es->plane == WESTON_PLANE_PRIMARY)
784                         drm_output_prepare_scanout_surface(output, es);
785                 if (es->plane == WESTON_PLANE_PRIMARY)
786                         drm_output_prepare_overlay_surface(output, es);
787
788         bail:
789                 if (es->plane == WESTON_PLANE_PRIMARY)
790                         pixman_region32_union(&overlap, &overlap,
791                                               &es->transform.boundingbox);
792
793                 if (prev_plane != WESTON_PLANE_PRIMARY &&
794                     es->plane == WESTON_PLANE_PRIMARY)
795                         weston_surface_damage(es);
796                 else if (prev_plane == WESTON_PLANE_PRIMARY &&
797                          es->plane != WESTON_PLANE_PRIMARY)
798                         weston_surface_damage_below(es);
799
800                 pixman_region32_fini(&surface_overlap);
801         }
802         pixman_region32_fini(&overlap);
803
804         if (drm_output->cursor_free)
805                 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
806
807         drm_disable_unused_sprites(output);
808 }
809
810 static void
811 drm_output_destroy(struct weston_output *output_base)
812 {
813         struct drm_output *output = (struct drm_output *) output_base;
814         struct drm_compositor *c =
815                 (struct drm_compositor *) output->base.compositor;
816         drmModeCrtcPtr origcrtc = output->original_crtc;
817
818         if (output->backlight)
819                 backlight_destroy(output->backlight);
820
821         /* Turn off hardware cursor */
822         drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
823
824         /* Restore original CRTC state */
825         drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
826                        origcrtc->x, origcrtc->y,
827                        &output->connector_id, 1, &origcrtc->mode);
828         drmModeFreeCrtc(origcrtc);
829
830         c->crtc_allocator &= ~(1 << output->crtc_id);
831         c->connector_allocator &= ~(1 << output->connector_id);
832
833         eglDestroySurface(c->base.egl_display, output->egl_surface);
834         gbm_surface_destroy(output->surface);
835
836         weston_output_destroy(&output->base);
837         wl_list_remove(&output->base.link);
838
839         free(output->name);
840         free(output);
841 }
842
843 static struct drm_mode *
844 choose_mode (struct drm_output *output, struct weston_mode *target_mode)
845 {
846         struct drm_mode *tmp_mode = NULL, *mode;
847
848         if (output->base.current->width == target_mode->width && 
849             output->base.current->height == target_mode->height &&
850             (output->base.current->refresh == target_mode->refresh ||
851              target_mode->refresh == 0))
852                 return (struct drm_mode *)output->base.current;
853
854         wl_list_for_each(mode, &output->base.mode_list, base.link) {
855                 if (mode->mode_info.hdisplay == target_mode->width &&
856                     mode->mode_info.vdisplay == target_mode->height) {
857                         if (mode->mode_info.vrefresh == target_mode->refresh || 
858                             target_mode->refresh == 0) {
859                                 return mode;
860                         } else if (!tmp_mode) 
861                                 tmp_mode = mode;
862                 }
863         }
864
865         return tmp_mode;
866 }
867
868 static int
869 drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
870 {
871         struct drm_output *output;
872         struct drm_mode *drm_mode;
873         int ret;
874         struct drm_compositor *ec;
875         struct gbm_surface *surface;
876         EGLSurface egl_surface;
877
878         if (output_base == NULL) {
879                 weston_log("output is NULL.\n");
880                 return -1;
881         }
882
883         if (mode == NULL) {
884                 weston_log("mode is NULL.\n");
885                 return -1;
886         }
887
888         ec = (struct drm_compositor *)output_base->compositor;
889         output = (struct drm_output *)output_base;
890         drm_mode  = choose_mode (output, mode);
891
892         if (!drm_mode) {
893                 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
894                 return -1;
895         } else if (&drm_mode->base == output->base.current) {
896                 return 0;
897         } else if (drm_mode->base.width == output->base.current->width &&
898                    drm_mode->base.height == output->base.current->height) {
899                 /* only change refresh value */
900                 ret = drmModeSetCrtc(ec->drm.fd,
901                                      output->crtc_id,
902                                      output->current->fb_id, 0, 0,
903                                      &output->connector_id, 1, &drm_mode->mode_info);
904
905                 if (ret) {
906                         weston_log("failed to set mode (%dx%d) %u Hz\n",
907                                 drm_mode->base.width,
908                                 drm_mode->base.height,
909                                 drm_mode->base.refresh / 1000);
910                         ret = -1;
911                 } else {
912                         output->base.current->flags = 0;
913                         output->base.current = &drm_mode->base;
914                         drm_mode->base.flags = 
915                                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
916                         ret = 0;
917                 }
918
919                 return ret;
920         }
921
922         drm_mode->base.flags =
923                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
924
925         surface = gbm_surface_create(ec->gbm,
926                                  drm_mode->base.width,
927                                  drm_mode->base.height,
928                                  GBM_FORMAT_XRGB8888,
929                                  GBM_BO_USE_SCANOUT |
930                                  GBM_BO_USE_RENDERING);
931         if (!surface) {
932                 weston_log("failed to create gbm surface\n");
933                 return -1;
934         }
935
936         egl_surface =
937                 eglCreateWindowSurface(ec->base.egl_display,
938                                        ec->base.egl_config,
939                                        surface, NULL);
940
941         if (egl_surface == EGL_NO_SURFACE) {
942                 weston_log("failed to create egl surface\n");
943                 goto err;
944         }
945
946         ret = drmModeSetCrtc(ec->drm.fd,
947                              output->crtc_id,
948                              output->current->fb_id, 0, 0,
949                              &output->connector_id, 1, &drm_mode->mode_info);
950         if (ret) {
951                 weston_log("failed to set mode\n");
952                 goto err;
953         }
954
955         /* reset rendering stuff. */
956         if (output->current) {
957                 if (output->current->is_client_buffer)
958                         gbm_bo_destroy(output->current->bo);
959                 else
960                         gbm_surface_release_buffer(output->surface,
961                                                    output->current->bo);
962         }
963         output->current = NULL;
964
965         if (output->next) {
966                 if (output->next->is_client_buffer)
967                         gbm_bo_destroy(output->next->bo);
968                 else
969                         gbm_surface_release_buffer(output->surface,
970                                                    output->next->bo);
971         }
972         output->next = NULL;
973
974         eglDestroySurface(ec->base.egl_display, output->egl_surface);
975         gbm_surface_destroy(output->surface);
976         output->egl_surface = egl_surface;
977         output->surface = surface;
978
979         /*update output*/
980         output->base.current = &drm_mode->base;
981         output->base.dirty = 1;
982         weston_output_move(&output->base, output->base.x, output->base.y);
983         return 0;
984
985 err:
986         eglDestroySurface(ec->base.egl_display, egl_surface);
987         gbm_surface_destroy(surface);
988         return -1;
989 }
990
991 static int
992 on_drm_input(int fd, uint32_t mask, void *data)
993 {
994         drmEventContext evctx;
995
996         memset(&evctx, 0, sizeof evctx);
997         evctx.version = DRM_EVENT_CONTEXT_VERSION;
998         evctx.page_flip_handler = page_flip_handler;
999         evctx.vblank_handler = vblank_handler;
1000         drmHandleEvent(fd, &evctx);
1001
1002         return 1;
1003 }
1004
1005 static int
1006 init_egl(struct drm_compositor *ec, struct udev_device *device)
1007 {
1008         EGLint major, minor, n;
1009         const char *filename, *sysnum;
1010         int fd;
1011         static const EGLint context_attribs[] = {
1012                 EGL_CONTEXT_CLIENT_VERSION, 2,
1013                 EGL_NONE
1014         };
1015
1016         static const EGLint config_attribs[] = {
1017                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1018                 EGL_RED_SIZE, 1,
1019                 EGL_GREEN_SIZE, 1,
1020                 EGL_BLUE_SIZE, 1,
1021                 EGL_ALPHA_SIZE, 0,
1022                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1023                 EGL_NONE
1024         };
1025
1026         sysnum = udev_device_get_sysnum(device);
1027         if (sysnum)
1028                 ec->drm.id = atoi(sysnum);
1029         if (!sysnum || ec->drm.id < 0) {
1030                 weston_log("cannot get device sysnum\n");
1031                 return -1;
1032         }
1033
1034         filename = udev_device_get_devnode(device);
1035         fd = open(filename, O_RDWR | O_CLOEXEC);
1036         if (fd < 0) {
1037                 /* Probably permissions error */
1038                 weston_log("couldn't open %s, skipping\n",
1039                         udev_device_get_devnode(device));
1040                 return -1;
1041         }
1042
1043         weston_log("using %s\n", filename);
1044
1045         ec->drm.fd = fd;
1046         ec->gbm = gbm_create_device(ec->drm.fd);
1047         ec->base.egl_display = eglGetDisplay(ec->gbm);
1048         if (ec->base.egl_display == NULL) {
1049                 weston_log("failed to create display\n");
1050                 return -1;
1051         }
1052
1053         if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
1054                 weston_log("failed to initialize display\n");
1055                 return -1;
1056         }
1057
1058         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
1059                 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
1060                 return -1;
1061         }
1062
1063         if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1064                              &ec->base.egl_config, 1, &n) || n != 1) {
1065                 weston_log("failed to choose config: %d\n", n);
1066                 return -1;
1067         }
1068
1069         ec->base.egl_context =
1070                 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1071                                  EGL_NO_CONTEXT, context_attribs);
1072         if (ec->base.egl_context == NULL) {
1073                 weston_log("failed to create context\n");
1074                 return -1;
1075         }
1076
1077         ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1078                                                GBM_FORMAT_XRGB8888,
1079                                                GBM_BO_USE_RENDERING);
1080         if (!ec->dummy_surface) {
1081                 weston_log("failed to create dummy gbm surface\n");
1082                 return -1;
1083         }
1084
1085         ec->dummy_egl_surface =
1086                 eglCreateWindowSurface(ec->base.egl_display,
1087                                        ec->base.egl_config,
1088                                        ec->dummy_surface,
1089                                        NULL);
1090         if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
1091                 weston_log("failed to create egl surface\n");
1092                 return -1;
1093         }
1094
1095         if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1096                             ec->dummy_egl_surface, ec->base.egl_context)) {
1097                 weston_log("failed to make context current\n");
1098                 return -1;
1099         }
1100
1101         return 0;
1102 }
1103
1104 static int
1105 drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1106 {
1107         struct drm_mode *mode;
1108         uint64_t refresh;
1109
1110         mode = malloc(sizeof *mode);
1111         if (mode == NULL)
1112                 return -1;
1113
1114         mode->base.flags = 0;
1115         mode->base.width = info->hdisplay;
1116         mode->base.height = info->vdisplay;
1117
1118         /* Calculate higher precision (mHz) refresh rate */
1119         refresh = (info->clock * 1000000LL / info->htotal +
1120                    info->vtotal / 2) / info->vtotal;
1121
1122         if (info->flags & DRM_MODE_FLAG_INTERLACE)
1123                 refresh *= 2;
1124         if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1125                 refresh /= 2;
1126         if (info->vscan > 1)
1127             refresh /= info->vscan;
1128
1129         mode->base.refresh = refresh;
1130         mode->mode_info = *info;
1131
1132         if (info->type & DRM_MODE_TYPE_PREFERRED)
1133                 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1134
1135         wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1136
1137         return 0;
1138 }
1139
1140 static int
1141 drm_subpixel_to_wayland(int drm_value)
1142 {
1143         switch (drm_value) {
1144         default:
1145         case DRM_MODE_SUBPIXEL_UNKNOWN:
1146                 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1147         case DRM_MODE_SUBPIXEL_NONE:
1148                 return WL_OUTPUT_SUBPIXEL_NONE;
1149         case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1150                 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1151         case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1152                 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1153         case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1154                 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1155         case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1156                 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1157         }
1158 }
1159
1160 static void
1161 sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
1162 {
1163         struct drm_sprite *sprite =
1164                 container_of(listener, struct drm_sprite,
1165                              destroy_listener);
1166         struct drm_compositor *compositor = sprite->compositor;
1167
1168         sprite->surface = NULL;
1169         drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1170         sprite->fb_id = 0;
1171 }
1172
1173 static void
1174 sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
1175 {
1176         struct drm_sprite *sprite =
1177                 container_of(listener, struct drm_sprite,
1178                              pending_destroy_listener);
1179         struct drm_compositor *compositor = sprite->compositor;
1180
1181         sprite->pending_surface = NULL;
1182         drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1183         sprite->pending_fb_id = 0;
1184 }
1185
1186 /* returns a value between 0-255 range, where higher is brighter */
1187 static uint32_t
1188 drm_get_backlight(struct drm_output *output)
1189 {
1190         long brightness, max_brightness, norm;
1191
1192         brightness = backlight_get_brightness(output->backlight);
1193         max_brightness = backlight_get_max_brightness(output->backlight);
1194
1195         /* convert it on a scale of 0 to 255 */
1196         norm = (brightness * 255)/(max_brightness);
1197
1198         return (uint32_t) norm;
1199 }
1200
1201 /* values accepted are between 0-255 range */
1202 static void
1203 drm_set_backlight(struct weston_output *output_base, uint32_t value)
1204 {
1205         struct drm_output *output = (struct drm_output *) output_base;
1206         long max_brightness, new_brightness;
1207
1208         if (!output->backlight)
1209                 return;
1210
1211         if (value > 255)
1212                 return;
1213
1214         max_brightness = backlight_get_max_brightness(output->backlight);
1215
1216         /* get denormalized value */
1217         new_brightness = (value * max_brightness) / 255;
1218
1219         backlight_set_brightness(output->backlight, new_brightness);
1220 }
1221
1222 static drmModePropertyPtr
1223 drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1224 {
1225         drmModePropertyPtr props;
1226         int i;
1227
1228         for (i = 0; i < connector->count_props; i++) {
1229                 props = drmModeGetProperty(fd, connector->props[i]);
1230                 if (!props)
1231                         continue;
1232
1233                 if (!strcmp(props->name, name))
1234                         return props;
1235
1236                 drmModeFreeProperty(props);
1237         }
1238
1239         return NULL;
1240 }
1241
1242 static void
1243 drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1244 {
1245         struct drm_output *output = (struct drm_output *) output_base;
1246         struct weston_compositor *ec = output_base->compositor;
1247         struct drm_compositor *c = (struct drm_compositor *) ec;
1248         drmModeConnectorPtr connector;
1249         drmModePropertyPtr prop;
1250
1251         connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1252         if (!connector)
1253                 return;
1254
1255         prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1256         if (!prop) {
1257                 drmModeFreeConnector(connector);
1258                 return;
1259         }
1260
1261         drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1262                                     prop->prop_id, level);
1263         drmModeFreeProperty(prop);
1264         drmModeFreeConnector(connector);
1265 }
1266
1267 static const char *connector_type_names[] = {
1268         "None",
1269         "VGA",
1270         "DVI",
1271         "DVI",
1272         "DVI",
1273         "Composite",
1274         "TV",
1275         "LVDS",
1276         "CTV",
1277         "DIN",
1278         "DP",
1279         "HDMI",
1280         "HDMI",
1281         "TV",
1282         "eDP",
1283 };
1284
1285 static int
1286 find_crtc_for_connector(struct drm_compositor *ec,
1287                         drmModeRes *resources, drmModeConnector *connector)
1288 {
1289         drmModeEncoder *encoder;
1290         uint32_t possible_crtcs;
1291         int i, j;
1292
1293         for (j = 0; j < connector->count_encoders; j++) {
1294                 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1295                 if (encoder == NULL) {
1296                         weston_log("Failed to get encoder.\n");
1297                         return -1;
1298                 }
1299                 possible_crtcs = encoder->possible_crtcs;
1300                 drmModeFreeEncoder(encoder);
1301
1302                 for (i = 0; i < resources->count_crtcs; i++) {
1303                         if (possible_crtcs & (1 << i) &&
1304                             !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1305                                 return i;
1306                 }
1307         }
1308
1309         return -1;
1310 }
1311
1312 static int
1313 create_output_for_connector(struct drm_compositor *ec,
1314                             drmModeRes *resources,
1315                             drmModeConnector *connector,
1316                             int x, int y, struct udev_device *drm_device)
1317 {
1318         struct drm_output *output;
1319         struct drm_mode *drm_mode, *next;
1320         struct weston_mode *m, *preferred, *current, *configured;
1321         struct drm_configured_output *o = NULL, *temp;
1322         drmModeEncoder *encoder;
1323         drmModeModeInfo crtc_mode;
1324         drmModeCrtc *crtc;
1325         int i, ret;
1326         char name[32];
1327         const char *type_name;
1328
1329         i = find_crtc_for_connector(ec, resources, connector);
1330         if (i < 0) {
1331                 weston_log("No usable crtc/encoder pair for connector.\n");
1332                 return -1;
1333         }
1334
1335         output = malloc(sizeof *output);
1336         if (output == NULL)
1337                 return -1;
1338
1339         memset(output, 0, sizeof *output);
1340         output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1341         output->base.make = "unknown";
1342         output->base.model = "unknown";
1343         wl_list_init(&output->base.mode_list);
1344
1345         if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1346                 type_name = connector_type_names[connector->connector_type];
1347         else
1348                 type_name = "UNKNOWN";
1349         snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1350         output->name = strdup(name);
1351
1352         output->crtc_id = resources->crtcs[i];
1353         ec->crtc_allocator |= (1 << output->crtc_id);
1354         output->connector_id = connector->connector_id;
1355         ec->connector_allocator |= (1 << output->connector_id);
1356
1357         output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1358
1359         /* Get the current mode on the crtc that's currently driving
1360          * this connector. */
1361         encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
1362         memset(&crtc_mode, 0, sizeof crtc_mode);
1363         if (encoder != NULL) {
1364                 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1365                 drmModeFreeEncoder(encoder);
1366                 if (crtc == NULL)
1367                         goto err_free;
1368                 if (crtc->mode_valid)
1369                         crtc_mode = crtc->mode;
1370                 drmModeFreeCrtc(crtc);
1371         }
1372
1373         for (i = 0; i < connector->count_modes; i++) {
1374                 ret = drm_output_add_mode(output, &connector->modes[i]);
1375                 if (ret)
1376                         goto err_free;
1377         }
1378
1379         preferred = NULL;
1380         current = NULL;
1381         configured = NULL;
1382
1383         wl_list_for_each(temp, &configured_output_list, link) {
1384                 if (strcmp(temp->name, output->name) == 0) {
1385                         weston_log("%s mode \"%s\" in config\n",
1386                                                         temp->name, temp->mode);
1387                         o = temp;
1388                         break;
1389                 }
1390         }
1391
1392         if (o && strcmp("off", o->mode) == 0) {
1393                 weston_log("Disabling output %s\n", o->name);
1394
1395                 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1396                                                         0, 0, 0, 0, 0, NULL);
1397                 goto err_free;
1398         }
1399
1400         wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
1401                 if (o && o->width == drm_mode->base.width &&
1402                         o->height == drm_mode->base.height &&
1403                         o->config == OUTPUT_CONFIG_MODE)
1404                         configured = &drm_mode->base;
1405                 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
1406                         current = &drm_mode->base;
1407                 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1408                         preferred = &drm_mode->base;
1409         }
1410
1411         if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1412                 ret = drm_output_add_mode(output, &o->crtc_mode);
1413                 if (ret)
1414                         goto err_free;
1415                 configured = container_of(output->base.mode_list.prev,
1416                                        struct weston_mode, link);
1417                 current = configured;
1418         }
1419
1420         if (current == NULL && crtc_mode.clock != 0) {
1421                 ret = drm_output_add_mode(output, &crtc_mode);
1422                 if (ret)
1423                         goto err_free;
1424                 current = container_of(output->base.mode_list.prev,
1425                                        struct weston_mode, link);
1426         }
1427
1428         if (o && o->config == OUTPUT_CONFIG_CURRENT)
1429                 configured = current;
1430
1431         if (option_current_mode && current)
1432                 output->base.current = current;
1433         else if (configured)
1434                 output->base.current = configured;
1435         else if (preferred)
1436                 output->base.current = preferred;
1437         else if (current)
1438                 output->base.current = current;
1439
1440         if (output->base.current == NULL) {
1441                 weston_log("no available modes for %s\n", output->name);
1442                 goto err_free;
1443         }
1444
1445         output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1446
1447         output->surface = gbm_surface_create(ec->gbm,
1448                                              output->base.current->width,
1449                                              output->base.current->height,
1450                                              GBM_FORMAT_XRGB8888,
1451                                              GBM_BO_USE_SCANOUT |
1452                                              GBM_BO_USE_RENDERING);
1453         if (!output->surface) {
1454                 weston_log("failed to create gbm surface\n");
1455                 goto err_free;
1456         }
1457
1458         output->egl_surface =
1459                 eglCreateWindowSurface(ec->base.egl_display,
1460                                        ec->base.egl_config,
1461                                        output->surface,
1462                                        NULL);
1463         if (output->egl_surface == EGL_NO_SURFACE) {
1464                 weston_log("failed to create egl surface\n");
1465                 goto err_surface;
1466         }
1467
1468         output->cursor_bo[0] =
1469                 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1470                               GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1471         output->cursor_bo[1] =
1472                 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1473                               GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1474
1475         output->backlight = backlight_init(drm_device,
1476                                            connector->connector_type);
1477         if (output->backlight) {
1478                 output->base.set_backlight = drm_set_backlight;
1479                 output->base.backlight_current = drm_get_backlight(output);
1480         }
1481
1482         weston_output_init(&output->base, &ec->base, x, y,
1483                            connector->mmWidth, connector->mmHeight,
1484                            WL_OUTPUT_FLIPPED);
1485
1486         wl_list_insert(ec->base.output_list.prev, &output->base.link);
1487
1488         output->base.origin = output->base.current;
1489         output->base.repaint = drm_output_repaint;
1490         output->base.destroy = drm_output_destroy;
1491         output->base.assign_planes = drm_assign_planes;
1492         output->base.set_dpms = drm_set_dpms;
1493         output->base.switch_mode = drm_output_switch_mode;
1494
1495         weston_log("Output %s, (connector %d, crtc %d)\n",
1496                    output->name, output->connector_id, output->crtc_id);
1497         wl_list_for_each(m, &output->base.mode_list, link)
1498                 weston_log_continue("  mode %dx%d@%.1f%s%s%s\n",
1499                                     m->width, m->height, m->refresh / 1000.0,
1500                                     m->flags & WL_OUTPUT_MODE_PREFERRED ?
1501                                     ", preferred" : "",
1502                                     m->flags & WL_OUTPUT_MODE_CURRENT ?
1503                                     ", current" : "",
1504                                     connector->count_modes == 0 ?
1505                                     ", built-in" : "");
1506
1507         return 0;
1508
1509 err_surface:
1510         gbm_surface_destroy(output->surface);
1511 err_free:
1512         wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1513                                                         base.link) {
1514                 wl_list_remove(&drm_mode->base.link);
1515                 free(drm_mode);
1516         }
1517
1518         drmModeFreeCrtc(output->original_crtc);
1519         ec->crtc_allocator &= ~(1 << output->crtc_id);
1520         ec->connector_allocator &= ~(1 << output->connector_id);
1521         free(output->name);
1522         free(output);
1523
1524         return -1;
1525 }
1526
1527 static void
1528 create_sprites(struct drm_compositor *ec)
1529 {
1530         struct drm_sprite *sprite;
1531         drmModePlaneRes *plane_res;
1532         drmModePlane *plane;
1533         uint32_t i;
1534
1535         plane_res = drmModeGetPlaneResources(ec->drm.fd);
1536         if (!plane_res) {
1537                 weston_log("failed to get plane resources: %s\n",
1538                         strerror(errno));
1539                 return;
1540         }
1541
1542         for (i = 0; i < plane_res->count_planes; i++) {
1543                 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1544                 if (!plane)
1545                         continue;
1546
1547                 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1548                                                    plane->count_formats));
1549                 if (!sprite) {
1550                         weston_log("%s: out of memory\n",
1551                                 __func__);
1552                         free(plane);
1553                         continue;
1554                 }
1555
1556                 memset(sprite, 0, sizeof *sprite);
1557
1558                 sprite->possible_crtcs = plane->possible_crtcs;
1559                 sprite->plane_id = plane->plane_id;
1560                 sprite->surface = NULL;
1561                 sprite->pending_surface = NULL;
1562                 sprite->fb_id = 0;
1563                 sprite->pending_fb_id = 0;
1564                 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1565                 sprite->pending_destroy_listener.notify =
1566                         sprite_handle_pending_buffer_destroy;
1567                 sprite->compositor = ec;
1568                 sprite->count_formats = plane->count_formats;
1569                 memcpy(sprite->formats, plane->formats,
1570                        plane->count_formats * sizeof(plane->formats[0]));
1571                 drmModeFreePlane(plane);
1572
1573                 wl_list_insert(&ec->sprite_list, &sprite->link);
1574         }
1575
1576         free(plane_res->planes);
1577         free(plane_res);
1578 }
1579
1580 static void
1581 destroy_sprites(struct drm_compositor *compositor)
1582 {
1583         struct drm_sprite *sprite, *next;
1584         struct drm_output *output;
1585
1586         output = container_of(compositor->base.output_list.next,
1587                               struct drm_output, base.link);
1588
1589         wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1590                 drmModeSetPlane(compositor->drm.fd,
1591                                 sprite->plane_id,
1592                                 output->crtc_id, 0, 0,
1593                                 0, 0, 0, 0, 0, 0, 0, 0);
1594                 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1595                 free(sprite);
1596         }
1597 }
1598
1599 static int
1600 create_outputs(struct drm_compositor *ec, uint32_t option_connector,
1601                struct udev_device *drm_device)
1602 {
1603         drmModeConnector *connector;
1604         drmModeRes *resources;
1605         int i;
1606         int x = 0, y = 0;
1607
1608         resources = drmModeGetResources(ec->drm.fd);
1609         if (!resources) {
1610                 weston_log("drmModeGetResources failed\n");
1611                 return -1;
1612         }
1613
1614         ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
1615         if (!ec->crtcs) {
1616                 drmModeFreeResources(resources);
1617                 return -1;
1618         }
1619
1620         ec->num_crtcs = resources->count_crtcs;
1621         memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1622
1623         for (i = 0; i < resources->count_connectors; i++) {
1624                 connector = drmModeGetConnector(ec->drm.fd,
1625                                                 resources->connectors[i]);
1626                 if (connector == NULL)
1627                         continue;
1628
1629                 if (connector->connection == DRM_MODE_CONNECTED &&
1630                     (option_connector == 0 ||
1631                      connector->connector_id == option_connector)) {
1632                         if (create_output_for_connector(ec, resources,
1633                                                         connector, x, y,
1634                                                         drm_device) < 0) {
1635                                 drmModeFreeConnector(connector);
1636                                 continue;
1637                         }
1638
1639                         x += container_of(ec->base.output_list.prev,
1640                                           struct weston_output,
1641                                           link)->current->width;
1642                 }
1643
1644                 drmModeFreeConnector(connector);
1645         }
1646
1647         if (wl_list_empty(&ec->base.output_list)) {
1648                 weston_log("No currently active connector found.\n");
1649                 drmModeFreeResources(resources);
1650                 return -1;
1651         }
1652
1653         drmModeFreeResources(resources);
1654
1655         return 0;
1656 }
1657
1658 static void
1659 update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
1660 {
1661         drmModeConnector *connector;
1662         drmModeRes *resources;
1663         struct drm_output *output, *next;
1664         int x = 0, y = 0;
1665         int x_offset = 0, y_offset = 0;
1666         uint32_t connected = 0, disconnects = 0;
1667         int i;
1668
1669         resources = drmModeGetResources(ec->drm.fd);
1670         if (!resources) {
1671                 weston_log("drmModeGetResources failed\n");
1672                 return;
1673         }
1674
1675         /* collect new connects */
1676         for (i = 0; i < resources->count_connectors; i++) {
1677                 int connector_id = resources->connectors[i];
1678
1679                 connector = drmModeGetConnector(ec->drm.fd, connector_id);
1680                 if (connector == NULL)
1681                         continue;
1682
1683                 if (connector->connection != DRM_MODE_CONNECTED) {
1684                         drmModeFreeConnector(connector);
1685                         continue;
1686                 }
1687
1688                 connected |= (1 << connector_id);
1689
1690                 if (!(ec->connector_allocator & (1 << connector_id))) {
1691                         struct weston_output *last =
1692                                 container_of(ec->base.output_list.prev,
1693                                              struct weston_output, link);
1694
1695                         /* XXX: not yet needed, we die with 0 outputs */
1696                         if (!wl_list_empty(&ec->base.output_list))
1697                                 x = last->x + last->current->width;
1698                         else
1699                                 x = 0;
1700                         y = 0;
1701                         create_output_for_connector(ec, resources,
1702                                                     connector, x, y,
1703                                                     drm_device);
1704                         weston_log("connector %d connected\n", connector_id);
1705
1706                 }
1707                 drmModeFreeConnector(connector);
1708         }
1709         drmModeFreeResources(resources);
1710
1711         disconnects = ec->connector_allocator & ~connected;
1712         if (disconnects) {
1713                 wl_list_for_each_safe(output, next, &ec->base.output_list,
1714                                       base.link) {
1715                         if (x_offset != 0 || y_offset != 0) {
1716                                 weston_output_move(&output->base,
1717                                                  output->base.x - x_offset,
1718                                                  output->base.y - y_offset);
1719                         }
1720
1721                         if (disconnects & (1 << output->connector_id)) {
1722                                 disconnects &= ~(1 << output->connector_id);
1723                                 weston_log("connector %d disconnected\n",
1724                                        output->connector_id);
1725                                 x_offset += output->base.current->width;
1726                                 drm_output_destroy(&output->base);
1727                         }
1728                 }
1729         }
1730
1731         /* FIXME: handle zero outputs, without terminating */   
1732         if (ec->connector_allocator == 0)
1733                 wl_display_terminate(ec->base.wl_display);
1734 }
1735
1736 static int
1737 udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
1738 {
1739         const char *sysnum;
1740         const char *val;
1741
1742         sysnum = udev_device_get_sysnum(device);
1743         if (!sysnum || atoi(sysnum) != ec->drm.id)
1744                 return 0;
1745
1746         val = udev_device_get_property_value(device, "HOTPLUG");
1747         if (!val)
1748                 return 0;
1749
1750         return strcmp(val, "1") == 0;
1751 }
1752
1753 static int
1754 udev_drm_event(int fd, uint32_t mask, void *data)
1755 {
1756         struct drm_compositor *ec = data;
1757         struct udev_device *event;
1758
1759         event = udev_monitor_receive_device(ec->udev_monitor);
1760
1761         if (udev_event_is_hotplug(ec, event))
1762                 update_outputs(ec, event);
1763
1764         udev_device_unref(event);
1765
1766         return 1;
1767 }
1768
1769 static void
1770 drm_restore(struct weston_compositor *ec)
1771 {
1772         struct drm_compositor *d = (struct drm_compositor *) ec;
1773
1774         if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1775                 weston_log("failed to drop master: %m\n");
1776         tty_reset(d->tty);
1777 }
1778
1779 static void
1780 drm_destroy(struct weston_compositor *ec)
1781 {
1782         struct drm_compositor *d = (struct drm_compositor *) ec;
1783         struct weston_seat *seat, *next;
1784         struct drm_configured_output *o, *n;
1785
1786         wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1787                 evdev_input_destroy(seat);
1788         wl_list_for_each_safe(o, n, &configured_output_list, link)
1789                 free(o);
1790
1791         wl_event_source_remove(d->udev_drm_source);
1792         wl_event_source_remove(d->drm_source);
1793
1794         weston_compositor_shutdown(ec);
1795
1796         /* Work around crash in egl_dri2.c's dri2_make_current() */
1797         eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1798                        EGL_NO_CONTEXT);
1799         eglTerminate(ec->egl_display);
1800         eglReleaseThread();
1801
1802         gbm_device_destroy(d->gbm);
1803         destroy_sprites(d);
1804         if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1805                 weston_log("failed to drop master: %m\n");
1806         tty_destroy(d->tty);
1807
1808         free(d);
1809 }
1810
1811 static void
1812 drm_compositor_set_modes(struct drm_compositor *compositor)
1813 {
1814         struct drm_output *output;
1815         struct drm_mode *drm_mode;
1816         int ret;
1817
1818         wl_list_for_each(output, &compositor->base.output_list, base.link) {
1819                 drm_mode = (struct drm_mode *) output->base.current;
1820                 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
1821                                      output->current->fb_id, 0, 0,
1822                                      &output->connector_id, 1,
1823                                      &drm_mode->mode_info);
1824                 if (ret < 0) {
1825                         weston_log(
1826                                 "failed to set mode %dx%d for output at %d,%d: %m\n",
1827                                 drm_mode->base.width, drm_mode->base.height, 
1828                                 output->base.x, output->base.y);
1829                 }
1830         }
1831 }
1832
1833 static void
1834 vt_func(struct weston_compositor *compositor, int event)
1835 {
1836         struct drm_compositor *ec = (struct drm_compositor *) compositor;
1837         struct weston_seat *seat;
1838         struct drm_sprite *sprite;
1839         struct drm_output *output;
1840
1841         switch (event) {
1842         case TTY_ENTER_VT:
1843                 compositor->focus = 1;
1844                 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
1845                         weston_log("failed to set master: %m\n");
1846                         wl_display_terminate(compositor->wl_display);
1847                 }
1848                 compositor->state = ec->prev_state;
1849                 drm_compositor_set_modes(ec);
1850                 weston_compositor_damage_all(compositor);
1851                 wl_list_for_each(seat, &compositor->seat_list, link) {
1852                         evdev_add_devices(ec->udev, seat);
1853                         evdev_enable_udev_monitor(ec->udev, seat);
1854                 }
1855                 break;
1856         case TTY_LEAVE_VT:
1857                 wl_list_for_each(seat, &compositor->seat_list, link) {
1858                         evdev_disable_udev_monitor(seat);
1859                         evdev_remove_devices(seat);
1860                 }
1861
1862                 compositor->focus = 0;
1863                 ec->prev_state = compositor->state;
1864                 compositor->state = WESTON_COMPOSITOR_SLEEPING;
1865
1866                 /* If we have a repaint scheduled (either from a
1867                  * pending pageflip or the idle handler), make sure we
1868                  * cancel that so we don't try to pageflip when we're
1869                  * vt switched away.  The SLEEPING state will prevent
1870                  * further attemps at repainting.  When we switch
1871                  * back, we schedule a repaint, which will process
1872                  * pending frame callbacks. */
1873
1874                 wl_list_for_each(output, &ec->base.output_list, base.link) {
1875                         output->base.repaint_needed = 0;
1876                         drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
1877                 }
1878
1879                 output = container_of(ec->base.output_list.next,
1880                                       struct drm_output, base.link);
1881
1882                 wl_list_for_each(sprite, &ec->sprite_list, link)
1883                         drmModeSetPlane(ec->drm.fd,
1884                                         sprite->plane_id,
1885                                         output->crtc_id, 0, 0,
1886                                         0, 0, 0, 0, 0, 0, 0, 0);
1887
1888                 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
1889                         weston_log("failed to drop master: %m\n");
1890
1891                 break;
1892         };
1893 }
1894
1895 static void
1896 switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
1897 {
1898         struct drm_compositor *ec = data;
1899
1900         tty_activate_vt(ec->tty, key - KEY_F1 + 1);
1901 }
1902
1903 static const char default_seat[] = "seat0";
1904
1905 static struct weston_compositor *
1906 drm_compositor_create(struct wl_display *display,
1907                       int connector, const char *seat, int tty,
1908                       int argc, char *argv[], const char *config_file)
1909 {
1910         struct drm_compositor *ec;
1911         struct udev_enumerate *e;
1912         struct udev_list_entry *entry;
1913         struct udev_device *device, *drm_device;
1914         const char *path, *device_seat;
1915         struct wl_event_loop *loop;
1916         struct weston_seat *weston_seat, *next;
1917         uint32_t key;
1918
1919         weston_log("initializing drm backend\n");
1920
1921         ec = malloc(sizeof *ec);
1922         if (ec == NULL)
1923                 return NULL;
1924         memset(ec, 0, sizeof *ec);
1925
1926         if (weston_compositor_init(&ec->base, display, argc, argv,
1927                                    config_file) < 0) {
1928                 weston_log("weston_compositor_init failed\n");
1929                 goto err_base;
1930         }
1931
1932         ec->udev = udev_new();
1933         if (ec->udev == NULL) {
1934                 weston_log("failed to initialize udev context\n");
1935                 goto err_compositor;
1936         }
1937
1938         ec->base.wl_display = display;
1939         ec->tty = tty_create(&ec->base, vt_func, tty);
1940         if (!ec->tty) {
1941                 weston_log("failed to initialize tty\n");
1942                 goto err_udev;
1943         }
1944
1945         e = udev_enumerate_new(ec->udev);
1946         udev_enumerate_add_match_subsystem(e, "drm");
1947         udev_enumerate_add_match_sysname(e, "card[0-9]*");
1948
1949         udev_enumerate_scan_devices(e);
1950         drm_device = NULL;
1951         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1952                 path = udev_list_entry_get_name(entry);
1953                 device = udev_device_new_from_syspath(ec->udev, path);
1954                 device_seat =
1955                         udev_device_get_property_value(device, "ID_SEAT");
1956                 if (!device_seat)
1957                         device_seat = default_seat;
1958                 if (strcmp(device_seat, seat) == 0) {
1959                         drm_device = device;
1960                         break;
1961                 }
1962                 udev_device_unref(device);
1963         }
1964
1965         if (drm_device == NULL) {
1966                 weston_log("no drm device found\n");
1967                 goto err_udev_enum;
1968         }
1969
1970         if (init_egl(ec, drm_device) < 0) {
1971                 weston_log("failed to initialize egl\n");
1972                 goto err_udev_dev;
1973         }
1974
1975         ec->base.destroy = drm_destroy;
1976         ec->base.restore = drm_restore;
1977
1978         ec->base.focus = 1;
1979
1980         ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
1981
1982         if (weston_compositor_init_gl(&ec->base) < 0)
1983                 goto err_egl;
1984
1985         for (key = KEY_F1; key < KEY_F9; key++)
1986                 weston_compositor_add_key_binding(&ec->base, key,
1987                                                   MODIFIER_CTRL | MODIFIER_ALT,
1988                                                   switch_vt_binding, ec);
1989
1990         wl_list_init(&ec->sprite_list);
1991         create_sprites(ec);
1992
1993         if (create_outputs(ec, connector, drm_device) < 0) {
1994                 weston_log("failed to create output for %s\n", path);
1995                 goto err_sprite;
1996         }
1997
1998         path = NULL;
1999
2000         evdev_input_create(&ec->base, ec->udev, seat);
2001
2002         loop = wl_display_get_event_loop(ec->base.wl_display);
2003         ec->drm_source =
2004                 wl_event_loop_add_fd(loop, ec->drm.fd,
2005                                      WL_EVENT_READABLE, on_drm_input, ec);
2006
2007         ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2008         if (ec->udev_monitor == NULL) {
2009                 weston_log("failed to intialize udev monitor\n");
2010                 goto err_drm_source;
2011         }
2012         udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2013                                                         "drm", NULL);
2014         ec->udev_drm_source =
2015                 wl_event_loop_add_fd(loop,
2016                                      udev_monitor_get_fd(ec->udev_monitor),
2017                                      WL_EVENT_READABLE, udev_drm_event, ec);
2018
2019         if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
2020                 weston_log("failed to enable udev-monitor receiving\n");
2021                 goto err_udev_monitor;
2022         }
2023
2024         udev_device_unref(drm_device);
2025         udev_enumerate_unref(e);
2026
2027         return &ec->base;
2028
2029 err_udev_monitor:
2030         wl_event_source_remove(ec->udev_drm_source);
2031         udev_monitor_unref(ec->udev_monitor);
2032 err_drm_source:
2033         wl_event_source_remove(ec->drm_source);
2034         wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2035                 evdev_input_destroy(weston_seat);
2036 err_sprite:
2037         destroy_sprites(ec);
2038 err_egl:
2039         eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2040                        EGL_NO_CONTEXT);
2041         eglTerminate(ec->base.egl_display);
2042         eglReleaseThread();
2043         gbm_device_destroy(ec->gbm);
2044 err_udev_dev:
2045         udev_device_unref(drm_device);
2046 err_udev_enum:
2047         udev_enumerate_unref(e);
2048         tty_destroy(ec->tty);
2049 err_udev:
2050         udev_unref(ec->udev);
2051 err_compositor:
2052         weston_compositor_shutdown(&ec->base);
2053 err_base:
2054         free(ec);
2055         return NULL;
2056 }
2057
2058 static int
2059 set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2060 {
2061         mode->flags = 0;
2062
2063         if (strcmp(hsync, "+hsync") == 0)
2064                 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2065         else if (strcmp(hsync, "-hsync") == 0)
2066                 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2067         else
2068                 return -1;
2069
2070         if (strcmp(vsync, "+vsync") == 0)
2071                 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2072         else if (strcmp(vsync, "-vsync") == 0)
2073                 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2074         else
2075                 return -1;
2076
2077         return 0;
2078 }
2079
2080 static int
2081 check_for_modeline(struct drm_configured_output *output)
2082 {
2083         drmModeModeInfo mode;
2084         char hsync[16];
2085         char vsync[16];
2086         char mode_name[16];
2087         float fclock;
2088
2089         mode.type = DRM_MODE_TYPE_USERDEF;
2090         mode.hskew = 0;
2091         mode.vscan = 0;
2092         mode.vrefresh = 0;
2093
2094         if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2095                                                 &fclock, &mode.hdisplay,
2096                                                 &mode.hsync_start,
2097                                                 &mode.hsync_end, &mode.htotal,
2098                                                 &mode.vdisplay,
2099                                                 &mode.vsync_start,
2100                                                 &mode.vsync_end, &mode.vtotal,
2101                                                 hsync, vsync) == 11) {
2102                 if (set_sync_flags(&mode, hsync, vsync))
2103                         return -1;
2104
2105                 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2106                 strcpy(mode.name, mode_name);
2107
2108                 mode.clock = fclock * 1000;
2109         } else
2110                 return -1;
2111
2112         output->crtc_mode = mode;
2113
2114         return 0;
2115 }
2116
2117 static void
2118 output_section_done(void *data)
2119 {
2120         struct drm_configured_output *output;
2121
2122         output = malloc(sizeof *output);
2123
2124         if (!output || !output_name || !output_mode) {
2125                 free(output_name);
2126                 output_name = NULL;
2127                 free(output_mode);
2128                 output_mode = NULL;
2129                 return;
2130         }
2131
2132         output->config = OUTPUT_CONFIG_INVALID;
2133         output->name = output_name;
2134         output->mode = output_mode;
2135
2136         if (strcmp(output_mode, "off") == 0)
2137                 output->config = OUTPUT_CONFIG_OFF;
2138         else if (strcmp(output_mode, "preferred") == 0)
2139                 output->config = OUTPUT_CONFIG_PREFERRED;
2140         else if (strcmp(output_mode, "current") == 0)
2141                 output->config = OUTPUT_CONFIG_CURRENT;
2142         else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2143                 output->config = OUTPUT_CONFIG_MODE;
2144         else if (check_for_modeline(output) == 0)
2145                 output->config = OUTPUT_CONFIG_MODELINE;
2146
2147         if (output->config != OUTPUT_CONFIG_INVALID)
2148                 wl_list_insert(&configured_output_list, &output->link);
2149         else {
2150                 free(output);
2151                 weston_log("Invalid mode \"%s\" for output %s\n",
2152                                                 output_mode, output_name);
2153         }
2154 }
2155
2156 WL_EXPORT struct weston_compositor *
2157 backend_init(struct wl_display *display, int argc, char *argv[],
2158              const char *config_file)
2159 {
2160         int connector = 0, tty = 0;
2161         const char *seat = default_seat;
2162
2163         const struct weston_option drm_options[] = {
2164                 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2165                 { WESTON_OPTION_STRING, "seat", 0, &seat },
2166                 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
2167                 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
2168         };
2169
2170         parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
2171
2172         wl_list_init(&configured_output_list);
2173
2174         const struct config_key drm_config_keys[] = {
2175                 { "name", CONFIG_KEY_STRING, &output_name },
2176                 { "mode", CONFIG_KEY_STRING, &output_mode },
2177         };
2178
2179         const struct config_section config_section[] = {
2180                 { "output", drm_config_keys,
2181                 ARRAY_LENGTH(drm_config_keys), output_section_done },
2182         };
2183
2184         parse_config_file(config_file, config_section,
2185                                 ARRAY_LENGTH(config_section), NULL);
2186
2187         return drm_compositor_create(display, connector, seat, tty, argc, argv,
2188                                      config_file);
2189 }