61cacc79b8ee4245a718fd760344ed414f6f91d2
[profile/ivi/weston-ivi-shell.git] / src / compositor-fbdev.c
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  * Copyright © 2012 Raspberry Pi Foundation
5  * Copyright © 2013 Philip Withnall
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of the copyright holders not be used in
12  * advertising or publicity pertaining to distribution of the software
13  * without specific, written prior permission.  The copyright holders make
14  * no representations about the suitability of this software for any
15  * purpose.  It is provided "as is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  */
25
26 #define _GNU_SOURCE
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <linux/fb.h>
38 #include <linux/input.h>
39
40 #include <libudev.h>
41
42 #include "config.h"
43
44 #include "compositor.h"
45 #include "launcher-util.h"
46 #include "pixman-renderer.h"
47 #include "udev-seat.h"
48
49 struct fbdev_compositor {
50         struct weston_compositor base;
51         uint32_t prev_state;
52
53         struct udev *udev;
54         struct tty *tty;
55 };
56
57 struct fbdev_screeninfo {
58         unsigned int x_resolution; /* pixels, visible area */
59         unsigned int y_resolution; /* pixels, visible area */
60         unsigned int width_mm; /* visible screen width in mm */
61         unsigned int height_mm; /* visible screen height in mm */
62         unsigned int bits_per_pixel;
63
64         size_t buffer_length; /* length of frame buffer memory in bytes */
65         size_t line_length; /* length of a line in bytes */
66         char id[16]; /* screen identifier */
67
68         pixman_format_code_t pixel_format; /* frame buffer pixel format */
69         unsigned int refresh_rate; /* Hertz */
70 };
71
72 struct fbdev_output {
73         struct fbdev_compositor *compositor;
74         struct weston_output base;
75
76         struct weston_mode mode;
77         struct wl_event_source *finish_frame_timer;
78
79         /* Frame buffer details. */
80         const char *device; /* ownership shared with fbdev_parameters */
81         struct fbdev_screeninfo fb_info;
82         void *fb; /* length is fb_info.buffer_length */
83
84         /* pixman details. */
85         pixman_image_t *hw_surface;
86         pixman_image_t *shadow_surface;
87         void *shadow_buf;
88         uint8_t depth;
89 };
90
91 struct fbdev_seat {
92         struct weston_seat base;
93         struct wl_list devices_list;
94
95         struct udev_monitor *udev_monitor;
96         struct wl_event_source *udev_monitor_source;
97         char *seat_id;
98 };
99
100 struct fbdev_parameters {
101         int tty;
102         char *device;
103 };
104
105 static const char default_seat[] = "seat0";
106
107 static inline struct fbdev_output *
108 to_fbdev_output(struct weston_output *base)
109 {
110         return container_of(base, struct fbdev_output, base);
111 }
112
113 static inline struct fbdev_seat *
114 to_fbdev_seat(struct weston_seat *base)
115 {
116         return container_of(base, struct fbdev_seat, base);
117 }
118
119 static inline struct fbdev_compositor *
120 to_fbdev_compositor(struct weston_compositor *base)
121 {
122         return container_of(base, struct fbdev_compositor, base);
123 }
124
125 static void
126 fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
127 {
128         struct fbdev_output *output = to_fbdev_output(base);
129         struct weston_compositor *ec = output->base.compositor;
130         pixman_box32_t *rects;
131         int nrects, i, src_x, src_y, x1, y1, x2, y2, width, height;
132
133         /* Repaint the damaged region onto the back buffer. */
134         pixman_renderer_output_set_buffer(base, output->shadow_surface);
135         ec->renderer->repaint_output(base, damage);
136
137         /* Transform and composite onto the frame buffer. */
138         width = pixman_image_get_width(output->shadow_surface);
139         height = pixman_image_get_height(output->shadow_surface);
140         rects = pixman_region32_rectangles(damage, &nrects);
141
142         for (i = 0; i < nrects; i++) {
143                 switch (base->transform) {
144                 default:
145                 case WL_OUTPUT_TRANSFORM_NORMAL:
146                         x1 = rects[i].x1;
147                         x2 = rects[i].x2;
148                         y1 = rects[i].y1;
149                         y2 = rects[i].y2;
150                         break;
151                 case WL_OUTPUT_TRANSFORM_180:
152                         x1 = width - rects[i].x2;
153                         x2 = width - rects[i].x1;
154                         y1 = height - rects[i].y2;
155                         y2 = height - rects[i].y1;
156                         break;
157                 case WL_OUTPUT_TRANSFORM_90:
158                         x1 = height - rects[i].y2;
159                         x2 = height - rects[i].y1;
160                         y1 = rects[i].x1;
161                         y2 = rects[i].x2;
162                         break;
163                 case WL_OUTPUT_TRANSFORM_270:
164                         x1 = rects[i].y1;
165                         x2 = rects[i].y2;
166                         y1 = width - rects[i].x2;
167                         y2 = width - rects[i].x1;
168                         break;
169                 }
170                 src_x = x1;
171                 src_y = y1;
172
173                 pixman_image_composite32(PIXMAN_OP_SRC,
174                         output->shadow_surface, /* src */
175                         NULL /* mask */,
176                         output->hw_surface, /* dest */
177                         src_x, src_y, /* src_x, src_y */
178                         0, 0, /* mask_x, mask_y */
179                         x1, y1, /* dest_x, dest_y */
180                         x2 - x1, /* width */
181                         y2 - y1 /* height */);
182         }
183
184         /* Update the damage region. */
185         pixman_region32_subtract(&ec->primary_plane.damage,
186                                  &ec->primary_plane.damage, damage);
187
188         /* Schedule the end of the frame. We do not sync this to the frame
189          * buffer clock because users who want that should be using the DRM
190          * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
191          * panning, which is broken in most kernel drivers.
192          *
193          * Finish the frame synchronised to the specified refresh rate. The
194          * refresh rate is given in mHz and the interval in ms. */
195         wl_event_source_timer_update(output->finish_frame_timer,
196                                      1000000 / output->mode.refresh);
197 }
198
199 static int
200 finish_frame_handler(void *data)
201 {
202         struct fbdev_output *output = data;
203         uint32_t msec;
204         struct timeval tv;
205
206         gettimeofday(&tv, NULL);
207         msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
208         weston_output_finish_frame(&output->base, msec);
209
210         return 1;
211 }
212
213 static pixman_format_code_t
214 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
215                         struct fb_fix_screeninfo *finfo)
216 {
217         /* Calculate the pixman format supported by the frame buffer from the
218          * buffer's metadata. Return 0 if no known pixman format is supported
219          * (since this has depth 0 it's guaranteed to not conflict with any
220          * actual pixman format).
221          *
222          * Documentation on the vinfo and finfo structures:
223          *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
224          *
225          * TODO: Try a bit harder to support other formats, including setting
226          * the preferred format in the hardware. */
227         int type;
228
229         weston_log("Calculating pixman format from:\n"
230                    STAMP_SPACE " - type: %i (aux: %i)\n"
231                    STAMP_SPACE " - visual: %i\n"
232                    STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
233                    STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
234                    STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
235                    STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
236                    STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
237                    finfo->type, finfo->type_aux, finfo->visual,
238                    vinfo->bits_per_pixel, vinfo->grayscale,
239                    vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
240                    vinfo->green.offset, vinfo->green.length,
241                    vinfo->green.msb_right,
242                    vinfo->blue.offset, vinfo->blue.length,
243                    vinfo->blue.msb_right,
244                    vinfo->transp.offset, vinfo->transp.length,
245                    vinfo->transp.msb_right);
246
247         /* We only handle packed formats at the moment. */
248         if (finfo->type != FB_TYPE_PACKED_PIXELS)
249                 return 0;
250
251         /* We only handle true-colour frame buffers at the moment. */
252         if (finfo->visual != FB_VISUAL_TRUECOLOR || vinfo->grayscale != 0)
253                 return 0;
254
255         /* We only support formats with MSBs on the left. */
256         if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
257             vinfo->blue.msb_right != 0)
258                 return 0;
259
260         /* Work out the format type from the offsets. We only support RGBA and
261          * ARGB at the moment. */
262         type = PIXMAN_TYPE_OTHER;
263
264         if ((vinfo->transp.offset >= vinfo->red.offset ||
265              vinfo->transp.length == 0) &&
266             vinfo->red.offset >= vinfo->green.offset &&
267             vinfo->green.offset >= vinfo->blue.offset)
268                 type = PIXMAN_TYPE_ARGB;
269         else if (vinfo->red.offset >= vinfo->green.offset &&
270                  vinfo->green.offset >= vinfo->blue.offset &&
271                  vinfo->blue.offset >= vinfo->transp.offset)
272                 type = PIXMAN_TYPE_RGBA;
273
274         if (type == PIXMAN_TYPE_OTHER)
275                 return 0;
276
277         /* Build the format. */
278         return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
279                              vinfo->transp.length,
280                              vinfo->red.length,
281                              vinfo->green.length,
282                              vinfo->blue.length);
283 }
284
285 static int
286 calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
287 {
288         uint64_t quot;
289
290         /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
291         quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
292         quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
293         quot *= vinfo->pixclock;
294
295         if (quot > 0) {
296                 uint64_t refresh_rate;
297
298                 refresh_rate = 1000000000000000LLU / quot;
299                 if (refresh_rate > 200000)
300                         refresh_rate = 200000; /* cap at 200 Hz */
301
302                 return refresh_rate;
303         }
304
305         return 60 * 1000; /* default to 60 Hz */
306 }
307
308 static int
309 fbdev_query_screen_info(struct fbdev_output *output, int fd,
310                         struct fbdev_screeninfo *info)
311 {
312         struct fb_var_screeninfo varinfo;
313         struct fb_fix_screeninfo fixinfo;
314
315         /* Probe the device for screen information. */
316         if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
317             ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
318                 return -1;
319         }
320
321         /* Store the pertinent data. */
322         info->x_resolution = varinfo.xres;
323         info->y_resolution = varinfo.yres;
324         info->width_mm = varinfo.width;
325         info->height_mm = varinfo.height;
326         info->bits_per_pixel = varinfo.bits_per_pixel;
327
328         info->buffer_length = fixinfo.smem_len;
329         info->line_length = fixinfo.line_length;
330         strncpy(info->id, fixinfo.id, sizeof(info->id) / sizeof(*info->id));
331
332         info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
333         info->refresh_rate = calculate_refresh_rate(&varinfo);
334
335         if (info->pixel_format == 0) {
336                 weston_log("Frame buffer uses an unsupported format.\n");
337                 return -1;
338         }
339
340         return 1;
341 }
342
343 static int
344 fbdev_set_screen_info(struct fbdev_output *output, int fd,
345                       struct fbdev_screeninfo *info)
346 {
347         struct fb_var_screeninfo varinfo;
348
349         /* Grab the current screen information. */
350         if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
351                 return -1;
352         }
353
354         /* Update the information. */
355         varinfo.xres = info->x_resolution;
356         varinfo.yres = info->y_resolution;
357         varinfo.width = info->width_mm;
358         varinfo.height = info->height_mm;
359         varinfo.bits_per_pixel = info->bits_per_pixel;
360
361         /* Try to set up an ARGB (x8r8g8b8) pixel format. */
362         varinfo.grayscale = 0;
363         varinfo.transp.offset = 24;
364         varinfo.transp.length = 0;
365         varinfo.transp.msb_right = 0;
366         varinfo.red.offset = 16;
367         varinfo.red.length = 8;
368         varinfo.red.msb_right = 0;
369         varinfo.green.offset = 8;
370         varinfo.green.length = 8;
371         varinfo.green.msb_right = 0;
372         varinfo.blue.offset = 0;
373         varinfo.blue.length = 8;
374         varinfo.blue.msb_right = 0;
375
376         /* Set the device's screen information. */
377         if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
378                 return -1;
379         }
380
381         return 1;
382 }
383
384 static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
385
386 /* Returns an FD for the frame buffer device. */
387 static int
388 fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
389                         struct fbdev_screeninfo *screen_info)
390 {
391         int fd = -1;
392
393         weston_log("Opening fbdev frame buffer.\n");
394
395         /* Open the frame buffer device. */
396         fd = open(fb_dev, O_RDWR | O_CLOEXEC);
397         if (fd < 0) {
398                 weston_log("Failed to open frame buffer device ‘%s’: %s\n",
399                            fb_dev, strerror(errno));
400                 return -1;
401         }
402
403         /* Grab the screen info. */
404         if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
405                 weston_log("Failed to get frame buffer info: %s\n",
406                            strerror(errno));
407
408                 close(fd);
409                 return -1;
410         }
411
412         return fd;
413 }
414
415 /* Closes the FD on success or failure. */
416 static int
417 fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
418 {
419         int retval = -1;
420
421         weston_log("Mapping fbdev frame buffer.\n");
422
423         /* Map the frame buffer. Write-only mode, since we don't want to read
424          * anything back (because it's slow). */
425         output->fb = mmap(NULL, output->fb_info.buffer_length,
426                           PROT_WRITE, MAP_SHARED, fd, 0);
427         if (output->fb == MAP_FAILED) {
428                 weston_log("Failed to mmap frame buffer: %s\n",
429                            strerror(errno));
430                 goto out_close;
431         }
432
433         /* Create a pixman image to wrap the memory mapped frame buffer. */
434         output->hw_surface =
435                 pixman_image_create_bits(output->fb_info.pixel_format,
436                                          output->fb_info.x_resolution,
437                                          output->fb_info.y_resolution,
438                                          output->fb,
439                                          output->fb_info.line_length);
440         if (output->hw_surface == NULL) {
441                 weston_log("Failed to create surface for frame buffer.\n");
442                 goto out_unmap;
443         }
444
445         /* Success! */
446         retval = 0;
447
448 out_unmap:
449         if (retval != 0 && output->fb != NULL)
450                 fbdev_frame_buffer_destroy(output);
451
452 out_close:
453         if (fd >= 0)
454                 close(fd);
455
456         return retval;
457 }
458
459 static void
460 fbdev_frame_buffer_destroy(struct fbdev_output *output)
461 {
462         weston_log("Destroying fbdev frame buffer.\n");
463
464         if (munmap(output->fb, output->fb_info.buffer_length) < 0)
465                 weston_log("Failed to munmap frame buffer: %s\n",
466                            strerror(errno));
467
468         output->fb = NULL;
469 }
470
471 static void fbdev_output_destroy(struct weston_output *base);
472 static void fbdev_output_disable(struct weston_output *base);
473
474 static int
475 fbdev_output_create(struct fbdev_compositor *compositor,
476                     const char *device)
477 {
478         struct fbdev_output *output;
479         pixman_transform_t transform;
480         int fb_fd;
481         int shadow_width, shadow_height;
482         int width, height;
483         unsigned int bytes_per_pixel;
484         struct wl_event_loop *loop;
485
486         weston_log("Creating fbdev output.\n");
487
488         output = calloc(1, sizeof *output);
489         if (!output)
490                 return -1;
491
492         output->compositor = compositor;
493         output->device = device;
494
495         /* Create the frame buffer. */
496         fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
497         if (fb_fd < 0) {
498                 weston_log("Creating frame buffer failed.\n");
499                 goto out_free;
500         }
501
502         if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
503                 weston_log("Mapping frame buffer failed.\n");
504                 goto out_free;
505         }
506
507         output->base.repaint = fbdev_output_repaint;
508         output->base.destroy = fbdev_output_destroy;
509         output->base.assign_planes = NULL;
510         output->base.set_backlight = NULL;
511         output->base.set_dpms = NULL;
512         output->base.switch_mode = NULL;
513
514         /* only one static mode in list */
515         output->mode.flags =
516                 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
517         output->mode.width = output->fb_info.x_resolution;
518         output->mode.height = output->fb_info.y_resolution;
519         output->mode.refresh = output->fb_info.refresh_rate;
520         wl_list_init(&output->base.mode_list);
521         wl_list_insert(&output->base.mode_list, &output->mode.link);
522
523         output->base.current = &output->mode;
524         output->base.origin = &output->mode;
525         output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
526         output->base.make = "unknown";
527         output->base.model = output->fb_info.id;
528
529         weston_output_init(&output->base, &compositor->base,
530                            0, 0, output->fb_info.width_mm,
531                            output->fb_info.height_mm,
532                            WL_OUTPUT_TRANSFORM_NORMAL);
533
534         width = output->fb_info.x_resolution;
535         height = output->fb_info.y_resolution;
536
537         pixman_transform_init_identity(&transform);
538         switch (output->base.transform) {
539         default:
540         case WL_OUTPUT_TRANSFORM_NORMAL:
541                 shadow_width = width;
542                 shadow_height = height;
543                 pixman_transform_rotate(&transform,
544                         NULL, 0, 0);
545                 pixman_transform_translate(&transform, NULL,
546                         0, 0);
547                 break;
548         case WL_OUTPUT_TRANSFORM_180:
549                 shadow_width = width;
550                 shadow_height = height;
551                 pixman_transform_rotate(&transform,
552                         NULL, -pixman_fixed_1, 0);
553                 pixman_transform_translate(NULL, &transform,
554                         pixman_int_to_fixed(shadow_width),
555                         pixman_int_to_fixed(shadow_height));
556                 break;
557         case WL_OUTPUT_TRANSFORM_270:
558                 shadow_width = height;
559                 shadow_height = width;
560                 pixman_transform_rotate(&transform,
561                         NULL, 0, pixman_fixed_1);
562                 pixman_transform_translate(&transform,
563                         NULL,
564                         pixman_int_to_fixed(shadow_width),
565                         0);
566                 break;
567         case WL_OUTPUT_TRANSFORM_90:
568                 shadow_width = height;
569                 shadow_height = width;
570                 pixman_transform_rotate(&transform,
571                         NULL, 0, -pixman_fixed_1);
572                 pixman_transform_translate(&transform,
573                         NULL,
574                         0,
575                         pixman_int_to_fixed(shadow_height));
576                 break;
577         }
578
579         bytes_per_pixel = output->fb_info.bits_per_pixel / 8;
580
581         output->shadow_buf = malloc(width * height * bytes_per_pixel);
582         output->shadow_surface =
583                 pixman_image_create_bits(output->fb_info.pixel_format,
584                                          shadow_width, shadow_height,
585                                          output->shadow_buf,
586                                          shadow_width * bytes_per_pixel);
587         if (output->shadow_buf == NULL || output->shadow_surface == NULL) {
588                 weston_log("Failed to create surface for frame buffer.\n");
589                 goto out_hw_surface;
590         }
591
592         /* No need in transform for normal output */
593         if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
594                 pixman_image_set_transform(output->shadow_surface, &transform);
595
596         if (pixman_renderer_output_create(&output->base) < 0)
597                 goto out_shadow_surface;
598
599         loop = wl_display_get_event_loop(compositor->base.wl_display);
600         output->finish_frame_timer =
601                 wl_event_loop_add_timer(loop, finish_frame_handler, output);
602
603         wl_list_insert(compositor->base.output_list.prev, &output->base.link);
604
605         weston_log("fbdev output %d×%d px\n",
606                    output->mode.width, output->mode.height);
607         weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
608                             output->mode.refresh / 1000);
609
610         return 0;
611
612 out_shadow_surface:
613         pixman_image_unref(output->shadow_surface);
614         output->shadow_surface = NULL;
615 out_hw_surface:
616         free(output->shadow_buf);
617         pixman_image_unref(output->hw_surface);
618         output->hw_surface = NULL;
619         weston_output_destroy(&output->base);
620         fbdev_frame_buffer_destroy(output);
621 out_free:
622         free(output);
623
624         return -1;
625 }
626
627 static void
628 fbdev_output_destroy(struct weston_output *base)
629 {
630         struct fbdev_output *output = to_fbdev_output(base);
631
632         weston_log("Destroying fbdev output.\n");
633
634         /* Close the frame buffer. */
635         fbdev_output_disable(base);
636
637         if (base->renderer_state != NULL)
638                 pixman_renderer_output_destroy(base);
639
640         if (output->shadow_surface != NULL) {
641                 pixman_image_unref(output->shadow_surface);
642                 output->shadow_surface = NULL;
643         }
644
645         if (output->shadow_buf != NULL) {
646                 free(output->shadow_buf);
647                 output->shadow_buf = NULL;
648         }
649
650         /* Remove the output. */
651         wl_list_remove(&output->base.link);
652         weston_output_destroy(&output->base);
653
654         free(output);
655 }
656
657 /* strcmp()-style return values. */
658 static int
659 compare_screen_info (const struct fbdev_screeninfo *a,
660                      const struct fbdev_screeninfo *b)
661 {
662         if (a->x_resolution == b->x_resolution &&
663             a->y_resolution == b->y_resolution &&
664             a->width_mm == b->width_mm &&
665             a->height_mm == b->height_mm &&
666             a->bits_per_pixel == b->bits_per_pixel &&
667             a->pixel_format == b->pixel_format &&
668             a->refresh_rate == b->refresh_rate)
669                 return 0;
670
671         return 1;
672 }
673
674 static int
675 fbdev_output_reenable(struct fbdev_compositor *compositor,
676                       struct weston_output *base)
677 {
678         struct fbdev_output *output = to_fbdev_output(base);
679         struct fbdev_screeninfo new_screen_info;
680         int fb_fd;
681
682         weston_log("Re-enabling fbdev output.\n");
683
684         /* Create the frame buffer. */
685         fb_fd = fbdev_frame_buffer_open(output, output->device,
686                                         &new_screen_info);
687         if (fb_fd < 0) {
688                 weston_log("Creating frame buffer failed.\n");
689                 goto err;
690         }
691
692         /* Check whether the frame buffer details have changed since we were
693          * disabled. */
694         if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
695                 /* Perform a mode-set to restore the old mode. */
696                 if (fbdev_set_screen_info(output, fb_fd,
697                                           &output->fb_info) < 0) {
698                         weston_log("Failed to restore mode settings. "
699                                    "Attempting to re-open output anyway.\n");
700                 }
701
702                 /* Remove and re-add the output so that resources depending on
703                  * the frame buffer X/Y resolution (such as the shadow buffer)
704                  * are re-initialised. */
705                 fbdev_output_destroy(base);
706                 fbdev_output_create(compositor, output->device);
707
708                 return 0;
709         }
710
711         /* Map the device if it has the same details as before. */
712         if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
713                 weston_log("Mapping frame buffer failed.\n");
714                 goto err;
715         }
716
717         return 0;
718
719 err:
720         return -1;
721 }
722
723 /* NOTE: This leaves output->fb_info populated, caching data so that if
724  * fbdev_output_reenable() is called again, it can determine whether a mode-set
725  * is needed. */
726 static void
727 fbdev_output_disable(struct weston_output *base)
728 {
729         struct fbdev_output *output = to_fbdev_output(base);
730
731         weston_log("Disabling fbdev output.\n");
732
733         if (output->hw_surface != NULL) {
734                 pixman_image_unref(output->hw_surface);
735                 output->hw_surface = NULL;
736         }
737
738         fbdev_frame_buffer_destroy(output);
739 }
740
741 static void
742 fbdev_compositor_destroy(struct weston_compositor *base)
743 {
744         struct fbdev_compositor *compositor = to_fbdev_compositor(base);
745         struct udev_seat *seat, *next;
746
747         /* Destroy all inputs. */
748         wl_list_for_each_safe(seat, next, &compositor->base.seat_list, base.link)
749                 udev_seat_destroy(seat);
750
751         /* Destroy the output. */
752         weston_compositor_shutdown(&compositor->base);
753
754         /* Chain up. */
755         compositor->base.renderer->destroy(&compositor->base);
756         tty_destroy(compositor->tty);
757
758         free(compositor);
759 }
760
761 static void
762 vt_func(struct weston_compositor *base, int event)
763 {
764         struct fbdev_compositor *compositor = to_fbdev_compositor(base);
765         struct udev_seat *seat;
766         struct weston_output *output;
767
768         switch (event) {
769         case TTY_ENTER_VT:
770                 weston_log("entering VT\n");
771                 compositor->base.focus = 1;
772                 compositor->base.state = compositor->prev_state;
773
774                 wl_list_for_each(output, &compositor->base.output_list, link) {
775                         fbdev_output_reenable(compositor, output);
776                 }
777
778                 weston_compositor_damage_all(&compositor->base);
779
780                 wl_list_for_each(seat, &compositor->base.seat_list, base.link)
781                         udev_seat_enable(seat, compositor->udev);
782                 break;
783         case TTY_LEAVE_VT:
784                 weston_log("leaving VT\n");
785                 wl_list_for_each(seat, &compositor->base.seat_list, base.link)
786                         udev_seat_disable(seat);
787
788                 wl_list_for_each(output, &compositor->base.output_list, link) {
789                         fbdev_output_disable(output);
790                 }
791
792                 compositor->base.focus = 0;
793                 compositor->prev_state = compositor->base.state;
794                 weston_compositor_offscreen(&compositor->base);
795
796                 /* If we have a repaint scheduled (from the idle handler), make
797                  * sure we cancel that so we don't try to pageflip when we're
798                  * vt switched away.  The OFFSCREEN state will prevent
799                  * further attemps at repainting.  When we switch
800                  * back, we schedule a repaint, which will process
801                  * pending frame callbacks. */
802
803                 wl_list_for_each(output,
804                                  &compositor->base.output_list, link) {
805                         output->repaint_needed = 0;
806                 }
807
808                 break;
809         };
810 }
811
812 static void
813 fbdev_restore(struct weston_compositor *base)
814 {
815         struct fbdev_compositor *compositor = to_fbdev_compositor(base);
816
817         tty_reset(compositor->tty);
818 }
819
820 static void
821 switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
822 {
823         struct fbdev_compositor *ec = data;
824
825         tty_activate_vt(ec->tty, key - KEY_F1 + 1);
826 }
827
828 static struct weston_compositor *
829 fbdev_compositor_create(struct wl_display *display, int *argc, char *argv[],
830                         const char *config_file, struct fbdev_parameters *param)
831 {
832         struct fbdev_compositor *compositor;
833         const char *seat = default_seat;
834         uint32_t key;
835
836         weston_log("initializing fbdev backend\n");
837
838         compositor = calloc(1, sizeof *compositor);
839         if (compositor == NULL)
840                 return NULL;
841
842         if (weston_compositor_init(&compositor->base, display, argc, argv,
843                                    config_file) < 0)
844                 goto out_free;
845
846         compositor->udev = udev_new();
847         if (compositor->udev == NULL) {
848                 weston_log("Failed to initialize udev context.\n");
849                 goto out_compositor;
850         }
851
852         /* Set up the TTY. */
853         compositor->tty = tty_create(&compositor->base, vt_func, param->tty);
854         if (!compositor->tty) {
855                 weston_log("Failed to initialize tty.\n");
856                 goto out_udev;
857         }
858
859         compositor->base.destroy = fbdev_compositor_destroy;
860         compositor->base.restore = fbdev_restore;
861
862         compositor->base.focus = 1;
863         compositor->prev_state = WESTON_COMPOSITOR_ACTIVE;
864
865         for (key = KEY_F1; key < KEY_F9; key++)
866                 weston_compositor_add_key_binding(&compositor->base, key,
867                                                   MODIFIER_CTRL | MODIFIER_ALT,
868                                                   switch_vt_binding,
869                                                   compositor);
870
871         if (pixman_renderer_init(&compositor->base) < 0)
872                 goto out_tty;
873
874         if (fbdev_output_create(compositor, param->device) < 0)
875                 goto out_pixman;
876
877         udev_seat_create(&compositor->base, compositor->udev, seat);
878
879         return &compositor->base;
880
881 out_pixman:
882         compositor->base.renderer->destroy(&compositor->base);
883
884 out_tty:
885         tty_destroy(compositor->tty);
886
887 out_udev:
888         udev_unref(compositor->udev);
889
890 out_compositor:
891         weston_compositor_shutdown(&compositor->base);
892
893 out_free:
894         free(compositor);
895
896         return NULL;
897 }
898
899 WL_EXPORT struct weston_compositor *
900 backend_init(struct wl_display *display, int *argc, char *argv[],
901              const char *config_file)
902 {
903         /* TODO: Ideally, available frame buffers should be enumerated using
904          * udev, rather than passing a device node in as a parameter. */
905         struct fbdev_parameters param = {
906                 .tty = 0, /* default to current tty */
907                 .device = "/dev/fb0", /* default frame buffer */
908         };
909
910         const struct weston_option fbdev_options[] = {
911                 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
912                 { WESTON_OPTION_STRING, "device", 0, &param.device },
913         };
914
915         parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
916
917         return fbdev_compositor_create(display, argc, argv, config_file,
918                                        &param);
919 }